feat: selector

This commit is contained in:
lisonge 2024-07-02 21:24:11 +08:00
parent 309165ae7b
commit e386168e67
5 changed files with 231 additions and 46 deletions

View File

@ -1,27 +1,35 @@
<script setup lang="ts">
import { shallowRef, computed } from 'vue';
import { useDebounce } from '@vueuse/core';
const value = shallowRef('');
const reg = /^[_a-zA-Z][a-zA-Z0-9_]*(\.[_a-zA-Z][a-zA-Z0-9_]*)*$/;
const reg = /^[_a-zA-Z][a-zA-Z0-9_]*$/;
const lazyValue = useDebounce(value, 300);
const test = computed(() => reg.test(lazyValue.value));
const test = computed(() => {
return (
lazyValue.value !== 'null' &&
lazyValue.value !== 'true' &&
lazyValue.value !== 'false' &&
reg.test(lazyValue.value)
);
});
</script>
<template>
<div>
<input
placeholder="请输入属性名测试是否合法"
placeholder="请输入标识符测试是否合法"
type="text"
v-model="value"
class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
/>
<div
mt-4px
mt-4px
:class="{
'color-red': !test,
'opacity-0': !lazyValue || !value,
}"
>
{{ test ? `合法属性名✅` : `非法属性名` }}
{{ test ? `合法标识符✅` : `非法标识符` }}
</div>
</div>
</template>

View File

@ -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,
},
],

View File

@ -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: 🏀 快照审查

View File

@ -1,10 +1,10 @@
# 高级选择器 {#title}
# 选择器 {#title}
<script setup>
import ValueField from '/.vitepress/components/ValueField.vue';
import IdentifierField from '/.vitepress/components/IdentifierField.vue';
</script>
一个类似 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`, 下面可输入属性名测试否是合法
值表达式分两类: 变量 和 字面量, 下图是关系表格
<table>
<thead>
<tr>
<th colspan="2"> <div text-center>值表达式</div> </th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="3">变量</td>
<td>标识符</td>
<td>
<code> a </code>
</td>
</tr>
<tr>
<td>成员表达式</td>
<td>
<code>a.b</code>
</td>
</tr>
<tr>
<td>调用表达式</td>
<td><code>a(b,c)</code></td>
</tr>
<tr>
<td rowspan="4">字面量</td>
<td>null</td>
<td><code>null</code></td>
</tr>
<tr>
<td>boolean</td>
<td><code>false</code></td>
</tr>
<tr>
<td>int</td>
<td><code>114514</code></td>
</tr>
<tr>
<td>string</td>
<td><code>'ikun'</code></td>
</tr>
</tbody>
</table>
每个值表达式都有其类型, 可细分为两类
基础类型: `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
<ValueField />
<IdentifierField />
:::
### 操作符 {#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 使用 ' &#96; " 之一成对包裹, 内部字符转义使用 `\`\
所有的转义字符示例 `\\`, `\'`, `\"`, `` \` ``, `\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 使用 ' &#96; " 之一成对包裹, 内部字符转义使用 `\`\
所有的转义字符示例 `\\`, `\'`, `\"`, `` \` ``, `\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}
关系选择器 由 关系操作符 和 关系表达式 构成, 用于连接两个属性选择器

78
docs/selector/node.md Normal file
View File

@ -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) 一致