pair-mode 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +2 -8
  3. package/README.md +71 -12
  4. package/assets/duck-appalled-banner-sprite.png +0 -0
  5. package/assets/duck-appalled-banner-v2-sprite.png +0 -0
  6. package/assets/duck-appalled-banner-v2.gif +0 -0
  7. package/assets/duck-appalled-sprite.png +0 -0
  8. package/assets/duck-appalled.gif +0 -0
  9. package/assets/duck-before-main.png +0 -0
  10. package/assets/duck.png +0 -0
  11. package/assets/favicon.png +0 -0
  12. package/assets/syntax/clojure.yaml +36 -0
  13. package/assets/syntax/cmake.yaml +41 -0
  14. package/assets/syntax/crystal.yaml +71 -0
  15. package/assets/syntax/csharp.yaml +51 -0
  16. package/assets/syntax/dart.yaml +45 -0
  17. package/assets/syntax/elm.yaml +38 -0
  18. package/assets/syntax/erb.yaml +42 -0
  19. package/assets/syntax/erlang.yaml +45 -0
  20. package/assets/syntax/fsharp.yaml +48 -0
  21. package/assets/syntax/graphql.yaml +47 -0
  22. package/assets/syntax/groovy.yaml +111 -0
  23. package/assets/syntax/haml.yaml +16 -0
  24. package/assets/syntax/haskell.yaml +52 -0
  25. package/assets/syntax/ini.yaml +23 -0
  26. package/assets/syntax/java.yaml +36 -0
  27. package/assets/syntax/julia.yaml +56 -0
  28. package/assets/syntax/kotlin.yaml +65 -0
  29. package/assets/syntax/makefile.yaml +37 -0
  30. package/assets/syntax/nginx.yaml +22 -0
  31. package/assets/syntax/nim.yaml +27 -0
  32. package/assets/syntax/nix.yaml +32 -0
  33. package/assets/syntax/objc.yaml +60 -0
  34. package/assets/syntax/ocaml.yaml +43 -0
  35. package/assets/syntax/perl.yaml +58 -0
  36. package/assets/syntax/php.yaml +60 -0
  37. package/assets/syntax/r.yaml +30 -0
  38. package/assets/syntax/scala.yaml +32 -0
  39. package/assets/syntax/svelte.yaml +27 -0
  40. package/assets/syntax/swift.yaml +102 -0
  41. package/assets/syntax/vue.yaml +63 -0
  42. package/assets/syntax/xml.yaml +37 -0
  43. package/assets/syntax/zig.yaml +52 -0
  44. package/dist/claude-code.js +463 -150
  45. package/dist/cli.js +1534 -459
  46. package/dist/codex.js +811 -394
  47. package/dist/opencode.js +455 -143
  48. package/dist/pair-tui.js +177 -27
  49. package/dist/pi.js +510 -156
  50. package/package.json +16 -17
  51. package/skills/toggle/SKILL.md +24 -0
  52. package/commands/pair.md +0 -18
  53. package/skills/pair/SKILL.md +0 -20
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-mode",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Hold every proposed edit, annotate the diff line by line, and hand the notes back to the agent.",
5
5
  "author": {
6
6
  "name": "ofrusch",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pair-mode",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Hold every proposed edit, annotate the diff line by line, and hand the notes back to the agent.",
5
5
  "author": {
6
6
  "name": "ofrusch",
@@ -8,13 +8,7 @@
8
8
  },
9
9
  "homepage": "https://github.com/oFrusch/pair-mode#readme",
10
10
  "license": "MIT",
11
- "keywords": [
12
- "code-review",
13
- "diff",
14
- "hooks",
15
- "pair-programming",
16
- "terminal"
17
- ],
11
+ "keywords": ["code-review", "diff", "hooks", "pair-programming", "terminal"],
18
12
  "hooks": "./hooks/codex.json",
19
13
  "skills": "./skills/",
20
14
  "interface": {
package/README.md CHANGED
@@ -1,8 +1,10 @@
1
- <img src="https://raw.githubusercontent.com/oFrusch/pair-mode/main/docs/images/duck.png" alt="The pair-mode duck" width="120" align="right">
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/oFrusch/pair-mode/main/assets/duck-appalled-banner-v2.gif" alt="A duck reacting to a diff full of deletions">
3
+ </p>
2
4
 
3
- # pair mode
5
+ <h1 align="center">pair mode</h1>
4
6
 
5
- #### For when your agent needs a rubber ducky.
7
+ <p align="center"><b>For when your agent needs a rubber ducky.</b></p>
6
8
 
7
9
  `pair-mode` is a tool that allows you to sit somewhere between being an approval monkey for your agent running in manual mode and just totally vibe coding in auto mode.
8
10
 
@@ -16,12 +18,10 @@ When enabled, your agent will push diffs to your editing interface of choice (yo
16
18
 
17
19
  ## Install
18
20
 
19
- ```
20
- npm install -g pair-mode
21
- pair-mode setup
22
- ```
21
+ Pick one of two paths. A plugin covers one CLI and needs no setup step. The npm install
22
+ covers every CLI on your machine and gives you the `pair-mode` command.
23
23
 
24
- ### Or install it as a plugin
24
+ ### As a plugin
25
25
 
26
26
  A plugin resolves its own path at runtime, so it needs no global install and no setup step.
27
27
 
@@ -29,7 +29,7 @@ Claude Code:
29
29
 
30
30
  ```
31
31
  /plugin marketplace add oFrusch/pair-mode
32
- /plugin install pair-mode
32
+ /plugin install pair-mode@pair-mode
33
33
  ```
34
34
 
35
35
  Codex:
@@ -39,9 +39,16 @@ codex plugin marketplace add oFrusch/pair-mode
39
39
  codex plugin add pair-mode@pair-mode
40
40
  ```
41
41
 
42
- The plugin registers the hook and the `/pair` command for that one CLI. Run
43
- `npm install -g pair-mode` as well if you want the `pair-mode` command on your PATH, which
44
- `pair-mode watch` and `pair-mode config` need.
42
+ The plugin registers the hook and the `pair` command for that one CLI. Add the npm install
43
+ below if you also want `pair-mode watch` or `pair-mode config`, because both need the
44
+ `pair-mode` command on your PATH.
45
+
46
+ ### From npm
47
+
48
+ ```
49
+ npm install -g pair-mode
50
+ pair-mode setup
51
+ ```
45
52
 
46
53
  Install pair-mode globally before you run setup. Setup writes the install path into each CLI's config as an absolute path. `npx pair-mode setup` runs from a package cache that npm later prunes, which would leave every hook pointing at a deleted file. Setup detects that case and stops.
47
54
 
@@ -81,6 +88,14 @@ This is what will render your diff if you choose to use one of the CLI-based app
81
88
  | nvim | Yes | Yes. Same `matchadd()` overlay as vim. |
82
89
  | nano | Yes | No. nano has no syntax engine here, so a changed row gets the diff band only. |
83
90
 
91
+ Pair mode names the language from the extension first, then the exact filename, then the
92
+ shebang on the first line. So `Gemfile`, `Dockerfile`, `Makefile`, and an extensionless
93
+ script all get colour. A brand new file has nothing on disk yet, so its first review reads
94
+ no shebang.
95
+
96
+ The pair pane and the web view colour every language Shiki bundles. micro colours the 54
97
+ languages that ship a syntax asset.
98
+
84
99
  Keys:
85
100
 
86
101
  - pair: see [Keymap](#keymap) below.
@@ -119,6 +134,50 @@ If you want to do all your development in one terminal pane while using either C
119
134
  Session mode moves the review out of the agent's process. The hook posts to a Unix
120
135
  socket and waits. A client you start (another terminal tab or the web view) renders the review and allows you to provide your annotations.
121
136
 
137
+ ### One socket per agent session
138
+
139
+ `pair-mode on` inside an agent session reads that session's id, turns pair mode on for that
140
+ session alone, and prints the session id. It mints no socket. Run `pair-mode watch <id>`
141
+ with the id it printed, and that watcher mints the socket. Another session in the same
142
+ checkout gets its own socket and never sees the first session's diffs.
143
+
144
+ `pair-mode on <dir>` from a plain terminal keeps the old behaviour. It writes a directory
145
+ flag, and its socket catches every session that has no socket of its own.
146
+
147
+ A bare `pair-mode off` inside a session turns pair mode off for that session only. It never
148
+ clears a directory flag, so it never silences another session. `pair-mode off <dir>` names
149
+ its target and clears the directory flag.
150
+
151
+ ### Finding a session
152
+
153
+ ```
154
+ pair-mode sessions
155
+ ```
156
+
157
+ That prints every live session with its id, its label, how many watchers are attached, and
158
+ how many reviews are queued. It also removes any socket whose watcher has died.
159
+
160
+ ```
161
+ pair-mode connect
162
+ ```
163
+
164
+ That opens the same list, interactive. `j`, `k`, and the arrow keys move the cursor. `Enter`
165
+ watches the session under the cursor. `q` quits.
166
+
167
+ `pair-mode watch <id>` attaches directly when you already know the id. It mints the socket
168
+ when nothing owns it yet, which is how a session first gets a watcher. An id that is not
169
+ `s-` followed by eight hex characters is rejected as a typo.
170
+
171
+ A session flag outlives the agent that wrote it. `pair-mode sessions` removes a session flag
172
+ and a session opt-out once the session has had no socket for fourteen days, and it says how
173
+ many it removed.
174
+
175
+ Several watchers can watch one session at once, in a terminal or in a browser. The first one
176
+ to watch a session owns its socket. Every later one attaches to that socket as a viewer. Each
177
+ attached client receives every diff, and the first answer wins. The others see the review
178
+ withdraw. A browser tab therefore joins a session a terminal pane already owns, and closing
179
+ the tab leaves that pane serving.
180
+
122
181
  ### Session mode config
123
182
 
124
183
  Set `transport` to `"session"`, then pick a client.
Binary file
Binary file
Binary file
package/assets/duck.png CHANGED
Binary file
Binary file
@@ -0,0 +1,36 @@
1
+ filetype: clojure
2
+
3
+ detect:
4
+ filename: "\\.(clj[sc]?|edn)$"
5
+
6
+ rules:
7
+ # Constants
8
+ - constant.bool: "\\b(true|false)\\b"
9
+ - constant.macro: "\\b(nil)\\b"
10
+ # Valid numbers
11
+ - constant.number: "[\\-]?[0-9]+?\\b"
12
+ - constant.number: "0x[0-9][A-Fa-f]+?\\b"
13
+ - constant.number: "[\\-]?(3[0-6]|2[0-9]|1[0-9]|[2-9])r[0-9A-Z]+?\\b"
14
+ # Invalid numbers
15
+ - error: "[\\-]?([4-9][0-9]|3[7-9]|1|0)r[0-9A-Z]+?\\b"
16
+
17
+ # Symbols
18
+ - symbol.operator: "[=>+\\-*/'?]"
19
+
20
+ # Types/casting
21
+ - type: "\\b(byte|short|(big)?int(eger)?|long|float|num|bigdec|rationalize)\\b"
22
+
23
+ # String highlighting
24
+ - constant.string:
25
+ start: '"'
26
+ end: '"'
27
+ skip: "\\\\."
28
+ rules:
29
+ - constant.specialChar: "(\\\\u[0-9A-fa-f]{4,4}|\\\\newline|\\\\space|\\\\tab|\\\\formfeed|\\\\backspace|\\\\return|\\\\.)"
30
+
31
+ # Comments
32
+ - comment:
33
+ start: ";"
34
+ end: "$"
35
+ rules:
36
+ - todo: "(TODO|XXX|FIXME):?"
@@ -0,0 +1,41 @@
1
+ filetype: cmake
2
+
3
+ detect:
4
+ filename: "(CMakeLists\\.txt|\\.cmake)$"
5
+
6
+ rules:
7
+ - identifier.var: "^[[:space:]]*[A-Z0-9_]+"
8
+ - preproc: "^[[:space:]]*(include|include_directories|include_external_msproject)\\b"
9
+
10
+ - statement: "^[[:space:]]*\\b((else|end)?if|else|(end)?while|(end)?foreach|break)\\b"
11
+ - statement: "\\b(COPY|NOT|COMMAND|PROPERTY|POLICY|TARGET|EXISTS|IS_(DIRECTORY|ABSOLUTE)|DEFINED)\\b[[:space:]]"
12
+ - statement: "[[:space:]]\\b(OR|AND|IS_NEWER_THAN|MATCHES|(STR|VERSION_)?(LESS|GREATER|EQUAL))\\b[[:space:]]"
13
+
14
+ - special: "^[[:space:]]*\\b((end)?(function|macro)|return)"
15
+
16
+ - constant.string:
17
+ start: '"'
18
+ end: '"'
19
+ skip: "\\\\."
20
+ rules:
21
+ - constant.specialChar: "\\\\."
22
+
23
+ - constant.string:
24
+ start: "'"
25
+ end: "'"
26
+ skip: "\\\\."
27
+ rules:
28
+ - constant.specialChar: "\\\\."
29
+
30
+ - preproc:
31
+ start: "\\$(\\{|ENV\\{)"
32
+ end: "\\}"
33
+ rules: []
34
+
35
+ - identifier.macro: "\\b(APPLE|UNIX|WIN32|CYGWIN|BORLAND|MINGW|MSVC(_IDE|60|71|80|90)?)\\b"
36
+
37
+ - comment:
38
+ start: "#"
39
+ end: "$"
40
+ rules:
41
+ - todo: "(TODO|XXX|FIXME):?"
@@ -0,0 +1,71 @@
1
+ filetype: crystal
2
+
3
+ detect:
4
+ filename: "\\.cr$"
5
+
6
+ rules:
7
+ # Asciibetical list of reserved words
8
+ - statement: "\\b(abstract|alias|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|in|include|instance_sizeof|lib|loop|macro|module|next|of|out|pointerof|private|protected|raise|require|rescue|return|select|self|sizeof|spawn|struct|super|then|type|typeof|uninitialized|union|unless|until|verbatim|when|while|with|yield)\\b"
9
+ # Constants
10
+ - constant: "\\b(true|false|nil)\\b"
11
+ - constant.number: "\\b[0-9]+\\b"
12
+ # Ones that can't be in the same regex because they include non-words.
13
+ # The nil? one has to be after the constants.
14
+ - statement: "\\b(nil\\?|as(\\?|\\b)|is_a\\?|responds_to\\?)"
15
+ - type: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*"
16
+ # Crystal "symbols"
17
+ - constant: "([ ]|^):[0-9A-Z_]+\\b"
18
+ # Some unique things we want to stand out
19
+ - constant: "\\b(__FILE__|__LINE__)\\b"
20
+ # Regular expressions
21
+ - constant: "/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*"
22
+
23
+ # Shell command expansion is in `backticks` or like %x{this}. These are
24
+ # "double-quotish" (to use a perlism).
25
+ - constant.string: "`[^`]*`|%x\\{[^}]*\\}"
26
+
27
+ - constant.string:
28
+ start: "`"
29
+ end: "`"
30
+ rules: []
31
+
32
+ - constant.string:
33
+ start: "%x\\{"
34
+ end: "\\}"
35
+ rules: []
36
+
37
+ - constant.string:
38
+ start: '"'
39
+ end: '"'
40
+ skip: "\\\\."
41
+ rules:
42
+ - constant.specialChar: "\\\\."
43
+ - symbol.brackets:
44
+ start: "#\\{"
45
+ end: "\\}"
46
+ rules:
47
+ - default: ".*"
48
+
49
+ - constant.string:
50
+ start: "'"
51
+ end: "'"
52
+ skip: "\\\\."
53
+ rules:
54
+ - constant.specialChar: "\\\\."
55
+
56
+ - comment:
57
+ start: "#"
58
+ end: "$"
59
+ rules:
60
+ - todo: "(TODO|XXX|FIXME):?"
61
+
62
+ - comment.bright:
63
+ start: "##"
64
+ end: "$"
65
+ rules:
66
+ - todo: "(TODO|XXX|FIXME):?"
67
+
68
+ - constant:
69
+ start: "<<-?'?EOT'?"
70
+ end: "^EOT"
71
+ rules: []
@@ -0,0 +1,51 @@
1
+ filetype: csharp
2
+
3
+ detect:
4
+ filename: "\\.cs$"
5
+
6
+ rules:
7
+ # Class
8
+ - identifier.class: "class +[A-Za-z0-9]+ *((:) +[A-Za-z0-9.]+)?"
9
+
10
+ # Annotation
11
+ - identifier.var: "@[A-Za-z]+"
12
+
13
+ - preproc: "^[[:space:]]*#[[:space:]]*(define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)"
14
+ - identifier: "([A-Za-z0-9_]*[[:space:]]*[()])"
15
+ - type: "\\b(bool|byte|sbyte|char|decimal|double|float|IntPtr|int|uint|long|ulong|managed|unmanaged|nint|nuint|object|short|ushort|string|base|this|var|void)\\b"
16
+ - statement: "\\b(alias|as|case|catch|checked|default|do|dynamic|else|finally|fixed|for|foreach|goto|if|is|lock|new|null|return|switch|throw|try|unchecked|when|while|with)\\b"
17
+ - statement: "\\b(abstract|add|and|args|async|await|class|const|delegate|enum|event|explicit|extern|file|get|global|implicit|in|init|internal|interface|nameof|namespace|not|notnull|operator|or|out|override|params|partial|private|protected|public|readonly|record|ref|remove|required|scoped|sealed|set|sizeof|stackalloc|static|struct|typeof|unsafe|using|value|virtual|volatile|yield)\\b"
18
+ # LINQ-only keywords (ones that cannot be used outside of a LINQ query - lots others can)
19
+ - statement: "\\b(from|where|select|group|info|orderby|join|let|in|on|equals|by|ascending|descending)\\b"
20
+ - special: "\\b(break|continue)\\b"
21
+ - constant.bool: "\\b(true|false)\\b"
22
+ - symbol.operator: "[\\-+/*=<>?:!~%&|]"
23
+ - constant.number: "\\b([0-9._]+|0x[A-Fa-f0-9_]+|0b[0-1_]+)[FL]?\\b"
24
+
25
+ - constant.string:
26
+ start: '"'
27
+ end: '"'
28
+ skip: "\\\\."
29
+ rules:
30
+ - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)"
31
+ - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}"
32
+
33
+ - constant.string:
34
+ start: "'"
35
+ end: "'"
36
+ skip: "\\\\."
37
+ rules:
38
+ - constant.specialChar: "\\\\([btnfr]|'|\\\"|\\\\)"
39
+ - constant.specialChar: "\\\\u[A-Fa-f0-9]{4}"
40
+
41
+ - comment:
42
+ start: "//"
43
+ end: "$"
44
+ rules:
45
+ - todo: "(TODO|XXX|FIXME):?"
46
+
47
+ - comment:
48
+ start: "/\\*"
49
+ end: "\\*/"
50
+ rules:
51
+ - todo: "(TODO|XXX|FIXME):?"
@@ -0,0 +1,45 @@
1
+ filetype: dart
2
+
3
+ detect:
4
+ filename: "\\.dart$"
5
+
6
+ rules:
7
+ - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b"
8
+ - constant.number: "\\b[-+]?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+)([EePp][+-]?[0-9]+)?[fFlL]?"
9
+ - constant.number: "\\b[-+]?([0-9]+[EePp][+-]?[0-9]+)[fFlL]?"
10
+ - identifier: "[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[(]"
11
+ - statement: "\\b(break|case|catch|continue|default|else|finally)\\b"
12
+ - statement: "\\b(for|function|get|if|in|as|is|new|return|set|switch|final|await|async|sync)\\b"
13
+ - statement: "\\b(switch|this|throw|try|var|void|while|with|import|library|part|const|export)\\b"
14
+ - constant: "\\b(true|false|null)\\b"
15
+ - type: "\\b(List|String)\\b"
16
+ - type: "\\b(int|num|double|bool)\\b"
17
+ - statement: "[-+/*=<>!~%?:&|]"
18
+ - constant: "/[^*]([^/]|(\\\\/))*[^\\\\]/[gim]*"
19
+ - constant: "\\\\[0-7][0-7]?[0-7]?|\\\\x[0-9a-fA-F]+|\\\\[bfnrt'\"\\?\\\\]"
20
+
21
+ - comment:
22
+ start: "//"
23
+ end: "$"
24
+ rules:
25
+ - todo: "TODO:?"
26
+
27
+ - comment:
28
+ start: "/\\*"
29
+ end: "\\*/"
30
+ rules:
31
+ - todo: "TODO:?"
32
+
33
+ - constant.string:
34
+ start: '"'
35
+ end: '"'
36
+ skip: "\\\\."
37
+ rules:
38
+ - constant.specialChar: "\\\\."
39
+
40
+ - constant.string:
41
+ start: "'"
42
+ end: "'"
43
+ skip: "\\\\."
44
+ rules:
45
+ - constant.specialChar: "\\\\."
@@ -0,0 +1,38 @@
1
+ filetype: elm
2
+
3
+ detect:
4
+ filename: "\\.elm$"
5
+
6
+ rules:
7
+ - statement: "\\b(as|alias|case|else|exposing|if|import|in|let|module|of|port|then|type|)\\b"
8
+ - statement: "(\\=|\\:|\\->)"
9
+ - type: "\\b([A-Z][A-Za-z\\d]*)\\b"
10
+ - identifier: "^([a-z][A-Za-z\\d]*)\\b"
11
+ - constant.string:
12
+ start: '"""'
13
+ end: '"""'
14
+ skip: "\\\\."
15
+ rules:
16
+ - constant.specialChar: "\\\\."
17
+ - constant.string:
18
+ start: '"'
19
+ end: '"'
20
+ skip: "\\\\."
21
+ rules:
22
+ - constant.specialChar: "\\\\."
23
+ - constant.string:
24
+ start: "'"
25
+ end: "'"
26
+ skip: "\\\\."
27
+ rules:
28
+ - constant.specialChar: "\\\\."
29
+ - comment:
30
+ start: "--"
31
+ end: "$"
32
+ rules:
33
+ - todo: "(TODO|XXX|FIXME):?"
34
+ - comment:
35
+ start: "\\{-"
36
+ end: "-\\}"
37
+ rules:
38
+ - todo: "(TODO|XXX|FIXME):?"
@@ -0,0 +1,42 @@
1
+ filetype: erb
2
+
3
+ detect:
4
+ filename: "\\.erb$|\\.rhtml$"
5
+
6
+ rules:
7
+ - error: "<[^!].*?>"
8
+ - symbol.tag: "(?i)<[/]?(a(bbr|cronym|ddress|pplet|rea|rticle|side|udio)?|b(ase(font)?|d(i|o)|ig|lockquote|r)?|ca(nvas|ption)|center|cite|co(de|l|lgroup)|d(ata(list)?|d|el|etails|fn|ialog|ir|l|t)|em(bed)?|fieldset|fig(caption|ure)|font|form|(i)?frame|frameset|h[1-6]|hr|i|img|in(put|s)|kbd|keygen|label|legend|li(nk)?|ma(in|p|rk)|menu(item)?|met(a|er)|nav|no(frames|script)|o(l|pt(group|ion)|utput)|p(aram|icture|re|rogress)?|q|r(p|t|uby)|s(trike)?|samp|se(ction|lect)|small|source|span|strong|su(b|p|mmary)|textarea|time|track|u(l)?|var|video|wbr)( .*|>)*?>"
9
+ - symbol.tag.extended: "(?i)<[/]?(body|div|html|head(er)?|footer|title|table|t(body|d|h(ead)?|r|foot))( .*|>)*?>"
10
+ - preproc: "(?i)<[/]?(script|style)( .*|>)*?>"
11
+ - special: "&[^;[[:space:]]]*;"
12
+ - symbol: "[:=]"
13
+ - identifier: "(alt|bgcolor|height|href|id|label|longdesc|name|onclick|onfocus|onload|onmouseover|size|span|src|style|target|type|value|width)="
14
+ - constant.string: '"[^"]*"'
15
+ - constant.number: "(?i)#[0-9a-fA-F]{6,6}"
16
+ - constant.string.url: "(ftp(s)?|http(s)?|git|chrome)://[^ ]+"
17
+ - comment: "<!--.+?-->"
18
+ - preproc: "<!DOCTYPE.+?>"
19
+ - default:
20
+ start: "<%"
21
+ end: "%>"
22
+ rules: []
23
+
24
+ - preproc: "<%|%>"
25
+ - red: "&[^;[[:space:]]]*;"
26
+ - statement: "\\b(BEGIN|END|alias|and|begin|break|case|class|def|defined\\?|do|else|elsif|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)\\b"
27
+ - identifier.var: "(\\$|@|@@)?\\b[A-Z]+[0-9A-Z_a-z]*"
28
+ - magenta: "(?i)([ ]|^):[0-9A-Z_]+\\b"
29
+ - identifier.macro: "\\b(__FILE__|__LINE__)\\b"
30
+ - brightmagenta: "!/([^/]|(\\\\/))*/[iomx]*|%r\\{([^}]|(\\\\}))*\\}[iomx]*"
31
+ - brightblue: "`[^`]*`|%x\\{[^}]*\\}"
32
+ - constant.string: "\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!"
33
+ - brightgreen: "#\\{[^}]*\\}"
34
+ - green: "'([^']|(\\\\'))*'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!"
35
+ - comment: "#[^{].*$|#$"
36
+ - comment.bright: "##[^{].*$|##$"
37
+ - identifier.macro:
38
+ start: "<<-?'?EOT'?"
39
+ end: "^EOT"
40
+ rules: []
41
+
42
+ - todo: "(XXX|TODO|FIXME|\\?\\?\\?)"
@@ -0,0 +1,45 @@
1
+ filetype: erlang
2
+
3
+ detect:
4
+ filename: "\\.erl$"
5
+
6
+ rules:
7
+ - identifier: "\\b[A-Z][0-9a-z_]*\\b"
8
+ # See: https://erlang.org/doc/reference_manual/data_types.html
9
+ - constant.number: "\\b[0-9]+(\\.[0-9]+)?(e-?[0-9]+)?\\b"
10
+ - constant.number: "\\b[0-9]{1,2}\\#[a-zA-Z0-9]+\\b"
11
+ - constant.bool: "\\b(true|false)\\b"
12
+ - constant.number: "\\$\\\\?\\S{1}"
13
+ # See: https://erlang.org/doc/reference_manual/introduction.html
14
+ - statement: "\\b(after|and|andalso|band|begin|bnot|bor|bsl|bsr|bxor|case|catch|cond|div|end|fun|if|let|not|of|or|orelse|receive|rem|try|when|xor)\\b"
15
+ # See: https://erlang.org/doc/reference_manual/macros.html
16
+ - preproc: "\\-(module|export|record|include|include_lib|define|undef|ifdef|ifndef|else|endif|if|elif|error|warning)\\b"
17
+ - identifier.macro: "\\?[A-Z0-9_]+\\b"
18
+ # See: https://erlang.org/doc/man/erlang.html
19
+ - special: "\\b(ext_binary|binary|iovec|message_queue_data|time(_unit|stamp)|abs|apply|atom(_to_binary|_to_list)|binary_(part|to_atom|to_existing_atom|to_float|to_integer|to_list|to_term)|bit(_size|string_to_list)|byte_size|ceil|check_(old_code|process_code)|date|delete_module|demonitor|disconnect_node|element|erase|error|exit|float(_to_binary|_to_list)?|floor|garbage_collect|get|group_leader|halt|integer(_to_binary|to_list)|iolist_(size|to_binary)|is_(alive|atom|binary|bitstring|boolean|float|function|integer|list|map|map_key|number|pid|port|process_alive|record|reference|tuple|length)|link|list_to_(atom|binary|bitstring|existing_atom|float|integer|pid|port|ref|tuple)|load_module|make_ref|map_(get|size)|max|min|module_loaded|monitor(_node)?|nodes?|now|open_port|pid_to_list|port(_close|command|connect|control|to_list)|pre_loaded|process(_flag|_info|es)|purge_module|put|register(ed)?|round|self|setelement|size|spawn(_link|_monitor|_opt|_binary)?|statistics|trunc|tuple_(size|to_list)|unlink|unregister|whereis)\\b"
20
+ # See: https://erlang.org/doc/reference_manual/data_types.html#atom
21
+ - symbol:
22
+ start: "'"
23
+ end: "'"
24
+ skip: "\\\\."
25
+ rules: []
26
+ # - constant.specialChar: "%."
27
+ # - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]"
28
+ # - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
29
+ - constant.string:
30
+ start: '"'
31
+ end: '"'
32
+ skip: "\\\\."
33
+ rules:
34
+ - constant.specialChar: "%."
35
+ - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]"
36
+ - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
37
+ - comment:
38
+ start: "\\(\\*"
39
+ end: "\\*\\)"
40
+ rules:
41
+ - todo: "(TODO|FIXME|WONTFIX|NOTE|HACK):?"
42
+ - comment:
43
+ start: "%"
44
+ end: "$"
45
+ rules: []
@@ -0,0 +1,48 @@
1
+ filetype: fsharp
2
+
3
+ detect:
4
+ filename: "\\.fs?$"
5
+
6
+ rules:
7
+ - identifier: "\\b[A-Z][0-9a-z_]{2,}\\b"
8
+ #declarations
9
+ - statement: "\\b(let|val|method|in|and|rec|private|virtual|constraint)\\b"
10
+ #structure items
11
+ - type: "\\b(type|open|class|module|exception|external)\\b"
12
+ #patterns
13
+ - statement: "\\b(fun|function|functor|match|try|with)\\b"
14
+ #patterns-modifiers
15
+ - statement: "\\b(as|when|of)\\b"
16
+ #conditions
17
+ - statement: "\\b(if|then|else)\\b"
18
+ #blocs
19
+ - type: "\\b(begin|end|object|struct|sig|for|while|do|done|to|downto)\\b"
20
+ #constantes
21
+ - constant.bool: "\\b(true|false)\\b"
22
+ #modules/classes
23
+ - special: "\\b(include|inherit|initializer)\\b"
24
+ #expr modifiers
25
+ - special: "\\b(new|ref|mutable|lazy|assert|raise)\\b"
26
+ #keywords which don't exist in ocaml
27
+ - type: "\\b(base|delegate|downcast|extern|finally|fixed|global|inline|interface|internal|let!|member|namespace|null|override|private|public)\\b"
28
+ - type: "\\b(return|return!|select|static|upcast|use|use!|void|yield|yield!)\\b"
29
+ - constant.string:
30
+ start: "'"
31
+ end: "'"
32
+ skip: "\\\\."
33
+ rules:
34
+ - constant.specialChar: "%."
35
+ - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]"
36
+ - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
37
+ - constant.string:
38
+ start: '"'
39
+ end: '"'
40
+ skip: "\\\\."
41
+ rules:
42
+ - constant.specialChar: "%."
43
+ - constant.specialChar: "\\\\[abfnrtv'\\\"\\\\]"
44
+ - constant.specialChar: "\\\\([0-7]{3}|x[A-Fa-f0-9]{2}|u[A-Fa-f0-9]{4}|U[A-Fa-f0-9]{8})"
45
+ - comment:
46
+ start: "\\(\\*"
47
+ end: "\\*\\)"
48
+ rules: []
@@ -0,0 +1,47 @@
1
+ filetype: graphql
2
+
3
+ detect:
4
+ filename: "\\.(gql|graphql)$"
5
+
6
+ rules:
7
+ - type: "\\b(?:(query|mutation|subscription|type|input|scalar|fragment|schema|union|on|extends?))\\b"
8
+
9
+ # scalar types
10
+ - statement: "\\b(ID|Int|Float|Boolean|String|Datetime|Null)\\b"
11
+
12
+ # introspection types
13
+ - statement: "(__\\w+)"
14
+
15
+ # parameters
16
+ - statement: "((\\w+)(?:\\:([\\s]*)?)(?:\\$))"
17
+
18
+ # directive locations
19
+ - statement: "\\b(QUERY|MUTATION|SUBSCRIPTION|FIELD|FRAGMENT_DEFINITION|FRAGMENT_SPREAD|INLINE_FRAGMENT|SCHEMA|SCALAR|OBJECT|FIELD_DEFINITION|ARGUMENT_DEFINITION|INTERFACE|UNION|ENUM|ENUM_VALUE|INPUT_OBJECT|INPUT_FIELD_DEFINITION)\\b"
20
+
21
+ # directives
22
+ - constant: "(@\\w+)"
23
+
24
+ # root types
25
+ - constant: "\\b(Query|Mutation|Subscription|Schema|Root)\\b"
26
+
27
+ # variables
28
+ - special: "(\\$\\w+)"
29
+
30
+ # required symbol
31
+ - special: "(!)"
32
+
33
+ - symbol: "(:|=|\\||\\(|\\)|\\{|\\}|\\[|\\])"
34
+
35
+ - constant.bool: "\\b(true|false)\\b"
36
+
37
+ - constant.string:
38
+ start: '"'
39
+ end: '"'
40
+ skip: "\\\\."
41
+ rules:
42
+ - constant.specialChar: "\\\\."
43
+
44
+ - comment:
45
+ start: "#"
46
+ end: "$"
47
+ rules: []