From e386168e67b236b7d9a120aa2151d6746fb6ea9c Mon Sep 17 00:00:00 2001 From: lisonge Date: Tue, 2 Jul 2024 21:24:11 +0800 Subject: [PATCH] feat: selector --- .../{ValueField.vue => IdentifierField.vue} | 18 +- docs/.vitepress/config.ts | 9 +- docs/index.md | 8 +- docs/selector/index.md | 164 ++++++++++++++---- docs/selector/node.md | 78 +++++++++ 5 files changed, 231 insertions(+), 46 deletions(-) rename docs/.vitepress/components/{ValueField.vue => IdentifierField.vue} (67%) create mode 100644 docs/selector/node.md diff --git a/docs/.vitepress/components/ValueField.vue b/docs/.vitepress/components/IdentifierField.vue similarity index 67% rename from docs/.vitepress/components/ValueField.vue rename to docs/.vitepress/components/IdentifierField.vue index 1d97f05..242d5bc 100644 --- a/docs/.vitepress/components/ValueField.vue +++ b/docs/.vitepress/components/IdentifierField.vue @@ -1,27 +1,35 @@ diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 61f74b5..bbdd1dd 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -41,15 +41,20 @@ export default defineConfig({ text: '指引', items: [ { text: '开始使用', link: '/guide/' }, - { text: '高级选择器', link: '/selector/' }, { text: '订阅规则', link: '/subscription/' }, { text: '疑难解答', link: '/faq/' }, ], }, + { + text: '选择器', + items: [ + { text: '语法介绍', link: '/selector/' }, + { text: '属性方法', link: '/selector/node' }, + ], + }, { text: 'API', link: '/api/', - collapsed: true, items: typedocSidebar, }, ], diff --git a/docs/index.md b/docs/index.md index d838b57..1f76084 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,13 +8,13 @@ titleTemplate: 自定义屏幕点击应用 hero: name: 'GKD' text: '自定义屏幕点击应用' - tagline: '基于无障碍+高级选择器+订阅规则' + tagline: '基于无障碍+选择器+订阅规则' actions: - theme: brand text: 开始使用 link: /guide/ - theme: alt - text: 高级选择器 + text: 选择器 link: /selector/ - theme: alt text: 订阅规则 @@ -29,8 +29,8 @@ hero: features: - title: 🐔 开放源代码 details: 任何人均可审查源代码, 确保安全性和质量 - - title: 🐋 高级选择器 - details: 一种能联系节点上下文信息的的高级选择器, 更容易也更精确找到目标节点 + - title: 🐋 选择器 + details: 一种能联系节点上下文信息的的查询语法, 更容易也更精确找到目标节点 - title: 🎤 订阅规则 details: 您可编写本地订阅满足自己需求, 远程订阅能让您直接使用大众维护的开源规则 - title: 🏀 快照审查 diff --git a/docs/selector/index.md b/docs/selector/index.md index f981da8..2d3925f 100644 --- a/docs/selector/index.md +++ b/docs/selector/index.md @@ -1,10 +1,10 @@ -# 高级选择器 {#title} +# 选择器 {#title} -一个类似 CSS 选择器的高级选择器, 能联系节点上下文信息, 更容易也更精确找到目标节点 +一个类似 CSS 选择器的选择器, 能联系节点上下文信息, 更容易也更精确找到目标节点 ## 为什么需要选择器 {#why} @@ -30,11 +30,11 @@ import ValueField from '/.vitepress/components/ValueField.vue'; 下面分别介绍 [属性选择器](#attr) 和 [关系选择器](#connect) -## 属性选择器 {#attr} +## 属性选择 {#attr} 它和 CSS 语法的 属性选择器很相似, 但更强大, 如下是一个示例 -`@TextView[a=1][b^='2'][c*='a'||d.length>7&&e=false]` +`@TextView[a=1][b^='2'][c*='a'||d.length>7&&e=false][!(f=true)][g.plus(1)>0]` `@` 表示选择此节点, 一条规则最后属性选择器 `@` 生效, 如果没有 `@`, 取最后一个属性选择器 @@ -44,28 +44,131 @@ import ValueField from '/.vitepress/components/ValueField.vue'; 为了方便书写规则, 上述 `TextView` 等价 `[name='TextView'||name$='.TextView']` -`[]` 内部是一个 逻辑表达式/布尔表达式 +`[]` 内部是一个 逻辑表达式/布尔表达式/取反表达式 - 逻辑表达式 -> `name='TextView'||name$='.TextView'` - 布尔表达式 -> `name='TextView'` +- 取反表达式 -> `!(name$='TextView')`, `!(name='TextView'||name$='.TextView')` -逻辑表达式 有两个操作符 `||` 和 `&&`. `&&` 优先级更高, 即 `[a>1||b>1&&c>1||d>1]` 等价于 `[a>1||(b>1&&c>1)||d>1]` +注意 取反表达式 后面必须是 `(...)`, `!!(...)` 是非法的 + +逻辑表达式 有两个操作符 `||` 和 `&&`. `&&` 优先级更高 + +即 `[a>1||b>1&&c>1||d>1]` 等价于 `[a>1||(b>1&&c>1)||d>1]` 并列的 `[]` 视为使用 `&&` 的逻辑表达式, 即 `[a=1][b=1]` 等价于 `[a=1&&b=1]` -布尔表达式 由 [属性名](#attr-name) [操作符](#attr-operator) [值](#attr-value) 顺序构成 +布尔表达式 由 `左值 操作符 右值` 构成, 左值/右值 是一个 值表达式 -### 属性名 {#attr-name} +下面分别介绍 [值表达式](#value-exp) 和 [操作符](#attr-operator) -正则匹配 `^[_a-zA-Z][a-zA-Z0-9_]*(\.[_a-zA-Z][a-zA-Z0-9_]*)*$` 的字符串 +## 值表达式 {#value-exp} -类似合法变量名 `a`/`a.length`, 下面可输入属性名测试否是合法 +值表达式分两类: 变量 和 字面量, 下图是关系表格 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
值表达式
示例
变量标识符 + a +
成员表达式 + a.b +
调用表达式a(b,c)
字面量nullnull
booleanfalse
int114514
string'ikun'
+ +每个值表达式都有其类型, 可细分为两类 + +基础类型: `null` `boolean` `int` `string` + +对象类型: `object` + +对象类型可细分为 `context` 和 `node` 两种类型 + +比如选择器 `[parent=null]` 代表选择一个父节点是 null 的节点, 即根节点 + +上面的 `parent` 属于 值表达式/变量/标识符, 类型是 `node` + +`context` 类型指代当前节点的上下文, 当想使用不属于 `node` 上的属性方法时就需要 `context` + +### 变量 {#var} + +首先需要了解 **标识符**: 正则匹配 `^[_a-zA-Z][a-zA-Z0-9_]*$` 并且不是 `null`/`true`/`false` 的字符串 + +示例合法变量名: `a` `ikun` `manbaout`, 下面可输入字符测试否是合法 ::: raw - + ::: -### 操作符 {#attr-operator} +--- + +接下来了解 **成员表达式** `a.b`, 它被 `.` 分为两个部分, 前部分是另一个变量, 后部分是一个标识符作为属性 + +同理 `a.b.c` 也是一个 成员表达式, 其中 `a.b` 是它的变量部分, `c` 是一个合法的标识符作为属性 + +根据上面标识符的规则, `a.1`, `a.null`, `a.true` 都是非法成员表达式 + +--- + +最后了解 **调用表达式** `a(b,c)`, 它由两个部分构成, `(` 的左侧 `a` 是一个变量作为 调用者 + +`(c,d)` 作为调用参数(值类型), 调用参数数量可以是 0 或任意个, 即 `a()` 也是合法的 + +合法的其它例子: `a.b(c,d).e(f).g(1,2,true)` + +需要注意调用者不能是 调用表达式, 即 `a()()` 非法 + +### 字面量 {#literal} + +根据上面的表格, 字面量有 4 种: `null`, `boolean`, `int`, `string` + +- null +- boolean 使用 `true`/`false` +- int 匹配 `^-?[0-9]$`, 即10进制自然数, 示例 `-1`,`0`,`1`, 不支持 `+1` 这种写法 +- string 使用 ' ` " 之一成对包裹, 内部字符转义使用 `\`\ + 所有的转义字符示例 `\\`, `\'`, `\"`, `` \` ``, `\n`, `\r`, `\t`, `\b`, `\xfF`, `\uffFF`\ + 不支持多行字符, 处于 `[0, 0x1F]` 的控制字符必须使用转义字符表示 + +此外使用 string 时需要了解 [嵌套转义字符](#nest-escape) 以避免出现错误 + +## 操作符 {#attr-operator} + +操作符 用于连接两个 值表达式 | 操作符 | 名称 | 说明 | | :----: | :-----------: | :-----------: | @@ -86,20 +189,7 @@ import ValueField from '/.vitepress/components/ValueField.vue'; 附加说明: `matches`/`notMatches` 要求 值 必须是合法的 [Java/Kotlin 正则表达式](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html), 否则提示语法错误 -### 值 {#attr-value} - -值: 4 种类型, `null`, `boolean`, `string`, `int` - -- null -- boolean 使用 `true`/`false` -- int 匹配 `^-?[0-9]$`, 即10进制自然数, 示例 `-1`,`0`,`1` -- string 使用 ' ` " 之一成对包裹, 内部字符转义使用 `\`\ - 所有的转义字符示例 `\\`, `\'`, `\"`, `` \` ``, `\n`, `\r`, `\t`, `\b`, `\xfF`, `\uffFF`\ - 不支持多行字符, 处于 `[0, 0x1F]` 的控制字符必须使用转义字符表示 - -此外使用 string 类型需要了解 [嵌套转义字符](#nest-escape) 以避免出现错误 - -操作符只能使用在对应的类型的值, 比如 `a>''` 类型不匹配, 将提示 `非法类型`/`非法选择器` +操作符只能使用在对应的类型的值, 比如 `a>''` 类型不匹配, 将提示 `非法类型` 下面表格中 `-` 表示类型不匹配 @@ -122,22 +212,26 @@ import ValueField from '/.vitepress/components/ValueField.vue'; 除 `=`/`!=` 以外的操作符, 当节点属性是 null 时表达式为 `false` -- a > 233 -- a >= 233 -- a < 233 -- a <= 233 -- a ^= 'xxx' +- a > 233 +- a >= 233 +- a < 233 +- a <= 233 +- a ^= 'xxx' - a !^= 'xxx' - a \*= 'xxx' - a !\* 'xxx' -- a $= 'xxx' +- a $= 'xxx' - a !$= 'xxx' -- a ~= 'xxx' +- a ~= 'xxx' - a !~= 'xxx' 即当 a 是 `null` 时以上表达式为 `false` -## 关系选择器 {#connect} +你可能会对 `a !$= 'xxx'` 在 a 是 `null` 表达式为 `false` 感到奇怪 + +那你可以换一种写法使用 `a=null || a!$='xxx'` 或 `!(a$='xxx')` + +## 关系选择 {#connect} 关系选择器 由 关系操作符 和 关系表达式 构成, 用于连接两个属性选择器 diff --git a/docs/selector/node.md b/docs/selector/node.md new file mode 100644 index 0000000..76072aa --- /dev/null +++ b/docs/selector/node.md @@ -0,0 +1,78 @@ +# 属性方法 {#title} + +此章节介绍各个类型可用的属性及其方法 + +> 注: `null` 无任何属性方法\ +> 所有的属性方法当调用者是 null 时, 均返回 null + +## boolean + +| 方法名 | 参数 | 返回类型 | 描述 | +| ------ | ---- | -------- | ----------- | +| toInt | | `int` | 转为 0 或 1 | + +## int + +| 方法名 | 参数 | 返回类型 | 描述 | +| -------- | ----- | ------------------- | -------------------- | +| toString | | [`string`](#string) | 转为10进制字符串 | +| toString | `int` | `string` | 转为对应进制的字符串 | +| plus | `int` | `string` | 加上 | +| minus | `int` | `string` | 减去 | +| times | `int` | `string` | 乘以 | +| div | `int` | `string` | 除以 | +| rem | `int` | `string` | 取余 | + +## string + +| 标识符 | 属性类型 | 描述 | +| ------ | ------------- | ---------- | +| length | [`int`](#int) | 字符串长度 | + +| 方法名 | 参数 | 返回类型 | 描述 | +| --------- | -------------- | -------- | ------------------------------------- | +| get | [`int`](#int) | `string` | 获取对应索引字符串 | +| at | `int` | `string` | 同上,但是参数传负数时从最后一个字符取 | +| substring | `int` | `string` | 截取指定索引到结尾字符串 | +| substring | `int`,`int` | `string` | 截取指定间隔字符串 | +| toInt | | `int` | 转为10进制数字 | +| toInt | `int` | `int` | 转为指定进制的数字 | +| indexOf | `string` | `int` | 查找指定字符串的索引 | +| indexOf | `string`,`int` | `int` | 从指定索引开始查找指定字符串的索引 | + +## node + +| 标识符 | 属性类型 | 描述 | +| ------------- | ------------------- | ---------- | +| \_id | [`int`](#int) | | +| \_pid | `int` | | +| id | [`string`](#string) | | +| vid | `string` | | +| name | `string` | | +| text | `string` | | +| desc | `string` | | +| clickable | `boolean` | | +| focusable | `boolean` | | +| checkable | `boolean` | | +| checked | `boolean` | | +| editable | `boolean` | | +| longClickable | `boolean` | | +| visibleToUser | `boolean` | | +| left | `int` | | +| top | `int` | | +| right | `int` | | +| bottom | `int` | | +| width | `int` | | +| height | `int` | | +| childCount | `int` | | +| index | `int` | | +| depth | `int` | | +| parent | [`node`](#node) | 获取父节点 | + +| 方法名 | 参数 | 返回类型 | 描述 | +| -------- | ---- | --------------- | -------------------- | +| getChild | int | [`node`](#node) | 获取指定索引的子节点 | + +## context + +属性方法暂与 [node](#node) 一致