init commit
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# Snippets
|
||||
|
||||
Custom format to represent snippets.
|
||||
|
||||
## Features
|
||||
|
||||
- Custom file ending `.snippet`.
|
||||
- Supports syntax highlighting in VSCode via an [extension](https://marketplace.visualstudio.com/items?itemName=AndreasArvidsson.andreas-talon)
|
||||
- Supports auto-formatting in VSCode via an [extension](https://marketplace.visualstudio.com/items?itemName=AndreasArvidsson.andreas-talon)
|
||||
- Support for insertion and wrapper snippets. Note that while the snippet file syntax here supports wrapper snippets, you will need to install [Cursorless](https://www.cursorless.org) for wrapper snippets to work.
|
||||
- Support for phrase formatters.
|
||||
|
||||
## Format
|
||||
|
||||
- A `.snippet` file can contain multiple snippet documents separated by `---`.
|
||||
- Each snippet document has a context and body separated by `-`.
|
||||
- Optionally a file can have a single context at the top with no body. This is not a snippet in itself, but default values to be inherited by the other snippet documents in the same file.
|
||||
- Some context keys supports multiple values. These values are separated by `|`.
|
||||
- For most keys like `language` or `phrase` multiple values means _or_. You can use phrase _1_ or phrase _2_. The snippet is active in language _A_ or language _B_.
|
||||
- For `insertionFormatter` multiple values means that the formatters will be applied in sequence.
|
||||
|
||||
### Context fields
|
||||
|
||||
| Key | Required | Multiple values | Example |
|
||||
| -------------- | -------- | --------------- | ------------------------------ |
|
||||
| name | Yes | No | `name: ifStatement` |
|
||||
| description | No | No | `description: My snippet` |
|
||||
| language | No | Yes | `language: javascript \| java` |
|
||||
| phrase | No | Yes | `phrase: if \| if state` |
|
||||
| insertionScope | No | Yes | `insertionScope: statement` |
|
||||
|
||||
- `name`: Unique name identifying the snippets. Can be referenced in Python to use the snippet programmatically.
|
||||
- `description`: A description of the snippet.
|
||||
- `language`: Language identifier indicating which language the snippet is available for. If omitted the snippet is enabled globally.
|
||||
- `phrase`: The spoken phrase used to insert the snippet. eg `"snip if"`.
|
||||
- `insertionScope`: Used by [Cursorless](https://www.cursorless.org) to infer scope when inserting the snippet. eg `"snip if after air"` gets inferred as `"snip if after state air"`.
|
||||
|
||||
### Variables
|
||||
|
||||
It's also possible to set configuration that applies to a specific tab stop (`$0`) or variable (`$try`):
|
||||
|
||||
| Key | Required | Multiple values | Example |
|
||||
| ------------------ | -------- | --------------- | ----------------------------------- |
|
||||
| insertionFormatter | No | Yes | `$0.insertionFormatter: SNAKE_CASE` |
|
||||
| wrapperPhrase | No | Yes | `$0.wrapperPhrase: try \| trying` |
|
||||
| wrapperScope | No | No | `$0.wrapperScope: statement` |
|
||||
|
||||
- `insertionFormatter`: Formatter to apply to the phrase when inserting the snippet. eg `"snip funk get value"`. If omitted no trailing phrase is available for the snippet.
|
||||
- `wrapperPhrase`: Used by [Cursorless](https://www.cursorless.org) as the spoken form for wrapping with the snippet. eg `"if wrap air"`. Without Cursorless this spoken form is ignored by Talon.
|
||||
- `wrapperScope`: Used by [Cursorless](https://www.cursorless.org) to infer scope when wrapping with the snippet. eg `"if wrap air"` gets inferred as `"if wrap state air"`.
|
||||
|
||||
## Formatting and syntax highlighting
|
||||
|
||||
To get formatting, code completion and syntax highlighting for `.snippet` files: install [andreas-talon](https://marketplace.visualstudio.com/items?itemName=AndreasArvidsson.andreas-talon)
|
||||
|
||||
## Examples
|
||||
|
||||
### Single snippet definition
|
||||
|
||||

|
||||
|
||||
### Multiple snippet definitions in single file
|
||||
|
||||

|
||||
|
||||
### Default context and multiple values
|
||||
|
||||

|
||||
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,66 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from talon import Context
|
||||
|
||||
|
||||
class SnippetLists:
|
||||
insertion: dict[str, str]
|
||||
with_phrase: dict[str, str]
|
||||
wrapper: dict[str, str]
|
||||
|
||||
def __init__(self):
|
||||
self.insertion = {}
|
||||
self.with_phrase = {}
|
||||
self.wrapper = {}
|
||||
|
||||
|
||||
@dataclass
|
||||
class SnippetLanguageState:
|
||||
ctx: Context
|
||||
lists: SnippetLists
|
||||
|
||||
|
||||
@dataclass
|
||||
class SnippetVariable:
|
||||
name: str
|
||||
insertion_formatters: list[str] | None = None
|
||||
wrapper_phrases: list[str] | None = None
|
||||
wrapper_scope: str | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Snippet:
|
||||
name: str
|
||||
body: str
|
||||
description: str | None
|
||||
phrases: list[str] | None
|
||||
insertion_scopes: list[str] | None
|
||||
languages: list[str] | None
|
||||
variables: list[SnippetVariable]
|
||||
|
||||
def get_variable(self, name: str):
|
||||
for var in self.variables:
|
||||
if var.name == name:
|
||||
return var
|
||||
return None
|
||||
|
||||
def get_variable_strict(self, name: str):
|
||||
variable = self.get_variable(name)
|
||||
if variable is None:
|
||||
raise ValueError(f"Snippet '{self.name}' has no variable '{name}'")
|
||||
return variable
|
||||
|
||||
|
||||
@dataclass
|
||||
class InsertionSnippet:
|
||||
body: str
|
||||
scopes: list[str] | None
|
||||
languages: list[str] | None
|
||||
|
||||
|
||||
@dataclass
|
||||
class WrapperSnippet:
|
||||
body: str
|
||||
variable_name: str
|
||||
scope: str | None
|
||||
languages: list[str] | None
|
||||
@@ -0,0 +1,224 @@
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from talon import Context, Module, actions, app, fs, settings
|
||||
|
||||
from ..modes.code_languages import code_languages
|
||||
from .snippet_types import (
|
||||
InsertionSnippet,
|
||||
Snippet,
|
||||
SnippetLanguageState,
|
||||
SnippetLists,
|
||||
WrapperSnippet,
|
||||
)
|
||||
from .snippets_parser import create_snippets_from_file
|
||||
|
||||
SNIPPETS_DIR = Path(__file__).parent / "snippets"
|
||||
|
||||
mod = Module()
|
||||
|
||||
mod.list("snippet", "List of insertion snippets")
|
||||
mod.list("snippet_with_phrase", "List of insertion snippets containing a text phrase")
|
||||
mod.list("snippet_wrapper", "List of wrapper snippets")
|
||||
|
||||
mod.setting(
|
||||
"snippets_dir",
|
||||
type=str,
|
||||
default=None,
|
||||
desc="Directory (relative to Talon user) containing additional snippets",
|
||||
)
|
||||
|
||||
# `_` represents the global context, ie snippets available regardless of language
|
||||
GLOBAL_ID = "_"
|
||||
|
||||
# { SNIPPET_NAME: Snippet[] }
|
||||
snippets_map: dict[str, list[Snippet]] = {}
|
||||
|
||||
# { LANGUAGE_ID: SnippetLanguageState }
|
||||
languages_state_map: dict[str, SnippetLanguageState] = {
|
||||
GLOBAL_ID: SnippetLanguageState(Context(), SnippetLists())
|
||||
}
|
||||
|
||||
# Create a context for each defined language
|
||||
for lang in code_languages:
|
||||
ctx = Context()
|
||||
ctx.matches = f"code.language: {lang.id}"
|
||||
languages_state_map[lang.id] = SnippetLanguageState(ctx, SnippetLists())
|
||||
|
||||
|
||||
def get_setting_dir():
|
||||
setting_dir = settings.get("user.snippets_dir")
|
||||
if not setting_dir:
|
||||
return None
|
||||
|
||||
dir = Path(setting_dir)
|
||||
|
||||
if not dir.is_absolute():
|
||||
user_dir = Path(actions.path.talon_user())
|
||||
dir = user_dir / dir
|
||||
|
||||
return dir.resolve()
|
||||
|
||||
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
def get_snippets(name: str) -> list[Snippet]:
|
||||
"""Get snippets named <name>"""
|
||||
if name not in snippets_map:
|
||||
raise ValueError(f"Unknown snippet '{name}'")
|
||||
return snippets_map[name]
|
||||
|
||||
def get_snippet(name: str) -> Snippet:
|
||||
"""Get snippet named <name> for the active language"""
|
||||
snippets: list[Snippet] = actions.user.get_snippets(name)
|
||||
return get_preferred_snippet(snippets)
|
||||
|
||||
def get_insertion_snippets(name: str) -> list[InsertionSnippet]:
|
||||
"""Get insertion snippets named <name>"""
|
||||
snippets: list[Snippet] = actions.user.get_snippets(name)
|
||||
return [
|
||||
InsertionSnippet(s.body, s.insertion_scopes, s.languages) for s in snippets
|
||||
]
|
||||
|
||||
def get_insertion_snippet(name: str) -> InsertionSnippet:
|
||||
"""Get insertion snippet named <name> for the active language"""
|
||||
snippet: Snippet = actions.user.get_snippet(name)
|
||||
return InsertionSnippet(
|
||||
snippet.body,
|
||||
snippet.insertion_scopes,
|
||||
snippet.languages,
|
||||
)
|
||||
|
||||
def get_wrapper_snippets(name: str) -> list[WrapperSnippet]:
|
||||
"""Get wrapper snippets named <name>"""
|
||||
snippet_name, variable_name = split_wrapper_snippet_name(name)
|
||||
snippets: list[Snippet] = actions.user.get_snippets(snippet_name)
|
||||
return [to_wrapper_snippet(s, variable_name) for s in snippets]
|
||||
|
||||
def get_wrapper_snippet(name: str) -> WrapperSnippet:
|
||||
"""Get wrapper snippet named <name> for the active language"""
|
||||
snippet_name, variable_name = split_wrapper_snippet_name(name)
|
||||
snippet: Snippet = actions.user.get_snippet(snippet_name)
|
||||
return to_wrapper_snippet(snippet, variable_name)
|
||||
|
||||
|
||||
def get_preferred_snippet(snippets: list[Snippet]) -> Snippet:
|
||||
lang: Union[str, set[str]] = actions.code.language()
|
||||
languages = [lang] if isinstance(lang, str) else lang
|
||||
|
||||
# First try to find a snippet matching the active language
|
||||
for snippet in snippets:
|
||||
if snippet.languages:
|
||||
for snippet_lang in snippet.languages:
|
||||
if snippet_lang in languages:
|
||||
return snippet
|
||||
|
||||
# Then look for a global snippet
|
||||
for snippet in snippets:
|
||||
if not snippet.languages:
|
||||
return snippet
|
||||
|
||||
raise ValueError(f"Snippet not available for language '{lang}'")
|
||||
|
||||
|
||||
def split_wrapper_snippet_name(name: str) -> tuple[str, str]:
|
||||
index = name.rindex(".")
|
||||
return name[:index], name[index + 1 :]
|
||||
|
||||
|
||||
def to_wrapper_snippet(snippet: Snippet, variable_name) -> WrapperSnippet:
|
||||
"""Get wrapper snippet named <name>"""
|
||||
var = snippet.get_variable_strict(variable_name)
|
||||
return WrapperSnippet(
|
||||
snippet.body,
|
||||
var.name,
|
||||
var.wrapper_scope,
|
||||
snippet.languages,
|
||||
)
|
||||
|
||||
|
||||
def update_snippets():
|
||||
global snippets_map
|
||||
|
||||
snippets = get_snippets_from_files()
|
||||
name_to_snippets: dict[str, list[Snippet]] = {}
|
||||
language_to_lists: dict[str, SnippetLists] = {}
|
||||
|
||||
for snippet in snippets:
|
||||
# Map snippet names to actual snippets
|
||||
name_to_snippets.setdefault(snippet.name, []).append(snippet)
|
||||
|
||||
# Map languages to phrase / name dicts
|
||||
for language in snippet.languages or [GLOBAL_ID]:
|
||||
lists = language_to_lists.setdefault(language, SnippetLists())
|
||||
|
||||
for phrase in snippet.phrases or []:
|
||||
lists.insertion[phrase] = snippet.name
|
||||
|
||||
for var in snippet.variables:
|
||||
if var.insertion_formatters:
|
||||
lists.with_phrase[phrase] = snippet.name
|
||||
|
||||
for var in snippet.variables:
|
||||
for phrase in var.wrapper_phrases or []:
|
||||
lists.wrapper[phrase] = f"{snippet.name}.{var.name}"
|
||||
|
||||
snippets_map = name_to_snippets
|
||||
update_contexts(language_to_lists)
|
||||
|
||||
|
||||
def update_contexts(language_to_lists: dict[str, SnippetLists]):
|
||||
global_lists = language_to_lists[GLOBAL_ID] or SnippetLists()
|
||||
|
||||
for lang, lists in language_to_lists.items():
|
||||
if lang not in languages_state_map:
|
||||
print(f"Found snippets for unknown language: {lang}")
|
||||
actions.app.notify(f"Found snippets for unknown language: {lang}")
|
||||
continue
|
||||
|
||||
state = languages_state_map[lang]
|
||||
insertion = {**global_lists.insertion, **lists.insertion}
|
||||
with_phrase = {**global_lists.with_phrase, **lists.with_phrase}
|
||||
wrapper = {**global_lists.wrapper, **lists.wrapper}
|
||||
updated_lists: dict[str, dict[str, str]] = {}
|
||||
|
||||
if state.lists.insertion != insertion:
|
||||
state.lists.insertion = insertion
|
||||
updated_lists["user.snippet"] = insertion
|
||||
|
||||
if state.lists.with_phrase != with_phrase:
|
||||
state.lists.with_phrase = with_phrase
|
||||
updated_lists["user.snippet_with_phrase"] = with_phrase
|
||||
|
||||
if state.lists.wrapper != wrapper:
|
||||
state.lists.wrapper = wrapper
|
||||
updated_lists["user.snippet_wrapper"] = wrapper
|
||||
|
||||
if updated_lists:
|
||||
state.ctx.lists.update(updated_lists)
|
||||
|
||||
|
||||
def get_snippets_from_files() -> list[Snippet]:
|
||||
setting_dir = get_setting_dir()
|
||||
result = []
|
||||
|
||||
for file in SNIPPETS_DIR.glob("**/*.snippet"):
|
||||
result.extend(create_snippets_from_file(file))
|
||||
|
||||
if setting_dir:
|
||||
for file in setting_dir.glob("**/*.snippet"):
|
||||
result.extend(create_snippets_from_file(file))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def on_ready():
|
||||
fs.watch(SNIPPETS_DIR, lambda _path, _flags: update_snippets())
|
||||
|
||||
if get_setting_dir():
|
||||
fs.watch(get_setting_dir(), lambda _path, _flags: update_snippets())
|
||||
|
||||
update_snippets()
|
||||
|
||||
|
||||
app.register("ready", on_ready)
|
||||
@@ -0,0 +1,6 @@
|
||||
snip {user.snippet}: user.insert_snippet_by_name(snippet)
|
||||
|
||||
snip {user.snippet_with_phrase} <user.text>:
|
||||
user.insert_snippet_by_name_with_phrase(snippet_with_phrase, text)
|
||||
|
||||
snip next: user.move_cursor_to_next_snippet_stop()
|
||||
@@ -0,0 +1,19 @@
|
||||
name: breakStatement
|
||||
phrase: break
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | rust
|
||||
-
|
||||
break;
|
||||
---
|
||||
|
||||
language: go | python | scala | stata | r
|
||||
-
|
||||
break
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
break $0
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: breakWithStatement
|
||||
phrase: break with
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact | php | rust
|
||||
-
|
||||
break $0;
|
||||
---
|
||||
@@ -0,0 +1,18 @@
|
||||
language: c | cpp
|
||||
---
|
||||
name: typedefStructDeclaration
|
||||
phrase: typedef struct
|
||||
$0.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
insertionScope: statement
|
||||
-
|
||||
typedef struct {
|
||||
$1
|
||||
} $0
|
||||
---
|
||||
|
||||
name: preprocessorPragmaStatement
|
||||
phrase: pre pragma | pragma
|
||||
insertionScope: statement
|
||||
-
|
||||
#pragma $0
|
||||
---
|
||||
@@ -0,0 +1,44 @@
|
||||
name: caseStatement
|
||||
phrase: case
|
||||
insertionScope: branch
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
case $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: python | php | go
|
||||
-
|
||||
case $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
when $1
|
||||
$0
|
||||
---
|
||||
|
||||
language: scala
|
||||
-
|
||||
case $1 => $0
|
||||
---
|
||||
|
||||
language: elixir
|
||||
-
|
||||
$1 ->
|
||||
$0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
$1 ~ $2,
|
||||
)
|
||||
---
|
||||
|
||||
language: kotlin
|
||||
-
|
||||
$1 -> $0
|
||||
---
|
||||
@@ -0,0 +1,46 @@
|
||||
name: catchStatement
|
||||
phrase: catch
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
catch (const std::exception& ex) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: java | csharp
|
||||
-
|
||||
catch(final Exception ex) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
catch(error) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
except Exception as ex:
|
||||
$0
|
||||
---
|
||||
|
||||
language: php
|
||||
-
|
||||
catch (\Throwable \$exception) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
warning = function(w) {
|
||||
$1
|
||||
}, error = function(e) {
|
||||
$0
|
||||
},
|
||||
---
|
||||
@@ -0,0 +1,49 @@
|
||||
name: classDeclaration
|
||||
phrase: class
|
||||
insertionScope: class | statement
|
||||
|
||||
$0.wrapperPhrase: class
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | kotlin
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
class $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
class $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: ruby
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
class $1
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: scala
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
class $1 ($0)
|
||||
---
|
||||
|
||||
language: cpp
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
class $1 {
|
||||
$0
|
||||
};
|
||||
---
|
||||
@@ -0,0 +1,23 @@
|
||||
name: codeBlock
|
||||
phrase: block
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | scala | kotlin | r | rust | go | css | scss | terraform | protobuf
|
||||
-
|
||||
{
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
:
|
||||
$0
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
|
||||
|
||||
$0
|
||||
---
|
||||
@@ -0,0 +1,28 @@
|
||||
name: commentBlock
|
||||
phrase: block comment
|
||||
insertionScope: statement
|
||||
|
||||
$0.insertionFormatter: CAPITALIZE_FIRST_WORD
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | scala | kotlin
|
||||
-
|
||||
/* $0 */
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
"""$0"""
|
||||
---
|
||||
|
||||
language: xml | html
|
||||
-
|
||||
<!-- $0 -->
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
--[[
|
||||
$0
|
||||
--]]
|
||||
---
|
||||
@@ -0,0 +1,21 @@
|
||||
name: commentDocumentation
|
||||
phrase: doc comment | doc string
|
||||
insertionScope: statement
|
||||
|
||||
$0.insertionFormatter: CAPITALIZE_FIRST_WORD
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php
|
||||
-
|
||||
/** $0 */
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
"""$0"""
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
/// $0
|
||||
---
|
||||
@@ -0,0 +1,45 @@
|
||||
name: commentLine
|
||||
phrase: comment
|
||||
|
||||
$0.insertionFormatter: CAPITALIZE_FIRST_WORD
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | json | java | javascript | typescript | javascriptreact | typescriptreact | php | go | scala | kotlin | rust
|
||||
-
|
||||
// $0
|
||||
---
|
||||
|
||||
language: python | talon | csv | elixir | terraform | ruby | r
|
||||
-
|
||||
# $0
|
||||
---
|
||||
|
||||
language: xml | html | markdown
|
||||
-
|
||||
<!-- $0 -->
|
||||
---
|
||||
|
||||
language: vimscript
|
||||
-
|
||||
"$0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
#$0
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
* $0
|
||||
---
|
||||
|
||||
language: sql | lua
|
||||
-
|
||||
-- $0
|
||||
---
|
||||
|
||||
language: batch
|
||||
-
|
||||
REM $0
|
||||
---
|
||||
@@ -0,0 +1,24 @@
|
||||
name: constructorDeclaration
|
||||
phrase: constructor
|
||||
insertionScope: namedFunction | statement
|
||||
---
|
||||
|
||||
language: cpp | csharp | java
|
||||
-
|
||||
$1($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
constructor($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
def __init__(self$1):
|
||||
$0
|
||||
---
|
||||
@@ -0,0 +1,24 @@
|
||||
name: continueStatement
|
||||
phrase: continue
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | rust
|
||||
-
|
||||
continue;
|
||||
---
|
||||
|
||||
language: go | python | scala | stata
|
||||
-
|
||||
continue
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
goto continue
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
next
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: continueWithLabelStatement
|
||||
phrase: continue with
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact | php | rust
|
||||
-
|
||||
continue $0;
|
||||
---
|
||||
@@ -0,0 +1,37 @@
|
||||
name: defaultStatement
|
||||
phrase: default
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | go
|
||||
-
|
||||
default:
|
||||
$0
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
case _:
|
||||
$0
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
else
|
||||
$0
|
||||
---
|
||||
|
||||
language: scala
|
||||
-
|
||||
case _ => $0
|
||||
---
|
||||
|
||||
language: elixir
|
||||
-
|
||||
_ ->
|
||||
$0
|
||||
---
|
||||
|
||||
language: kotlin
|
||||
-
|
||||
else -> $0
|
||||
---
|
||||
@@ -0,0 +1,33 @@
|
||||
name: doWhileLoopStatement
|
||||
phrase: do while
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
do {
|
||||
$0
|
||||
} while($1);
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
repeat
|
||||
$0
|
||||
until $1
|
||||
---
|
||||
|
||||
language: php
|
||||
-
|
||||
do {
|
||||
$0
|
||||
} while ($1);
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
loop do
|
||||
$0
|
||||
break if $1
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,12 @@
|
||||
language: elixir
|
||||
---
|
||||
|
||||
name: conditionStatement
|
||||
phrase: cond
|
||||
insertionScope: statement
|
||||
-
|
||||
cond do
|
||||
$1 ->
|
||||
$0
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,54 @@
|
||||
name: elseIfStatement
|
||||
phrase: elif
|
||||
insertionScope: statement
|
||||
|
||||
$1.wrapperPhrase: elif cond
|
||||
$1.wrapperScope: statement
|
||||
$0.wrapperPhrase: elif
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | scala | kotlin | r
|
||||
-
|
||||
else if ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
elif $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
elseif $1 then
|
||||
$0
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
elsif $1
|
||||
$0
|
||||
---
|
||||
|
||||
language: vimscript
|
||||
-
|
||||
elseif $1
|
||||
$0
|
||||
---
|
||||
|
||||
language: php
|
||||
-
|
||||
elseif ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: stata | go | rust
|
||||
-
|
||||
else if $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,38 @@
|
||||
name: elseStatement
|
||||
phrase: else
|
||||
insertionScope: statement
|
||||
|
||||
$0.wrapperPhrase: else
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | r | php | stata | go | scala | kotlin | rust
|
||||
-
|
||||
else {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
else:
|
||||
$0
|
||||
---
|
||||
|
||||
language: lua | elixir
|
||||
-
|
||||
else
|
||||
$0
|
||||
---
|
||||
|
||||
language: vimscript
|
||||
-
|
||||
else
|
||||
$0
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
else
|
||||
$0
|
||||
---
|
||||
@@ -0,0 +1,24 @@
|
||||
name: finallyStatement
|
||||
phrase: finally
|
||||
---
|
||||
|
||||
language: csharp | java | javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
finally {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
finally:
|
||||
$0
|
||||
---
|
||||
|
||||
|
||||
language: r
|
||||
-
|
||||
finally = {
|
||||
$0
|
||||
})
|
||||
---
|
||||
@@ -0,0 +1,25 @@
|
||||
name: forEachMutableStatement
|
||||
phrase: for each mute | each mute
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
for (auto &$1 : $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
for ($1 : $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
for ($1 of $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,104 @@
|
||||
name: forEachStatement
|
||||
phrase: for each | each
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
for (const auto &$1 : $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: csharp
|
||||
-
|
||||
foreach ($1 in $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
for (final $1 : $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
for (const $1 of $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
for $1 in $2:
|
||||
$0
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
for $1 in $2 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
for $1 in $2 do
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
.each do |$1|
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: scala
|
||||
-
|
||||
for ($1 <- $0)
|
||||
---
|
||||
|
||||
language: terraform
|
||||
-
|
||||
for $1 in $2 : $0
|
||||
---
|
||||
|
||||
language: go
|
||||
-
|
||||
for $1 := range $2 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: php
|
||||
-
|
||||
foreach ($1 as $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: r | kotlin
|
||||
-
|
||||
for ($1 in $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
foreach $1 in $2 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
for ($1 in $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,69 @@
|
||||
name: forLoopStatement
|
||||
phrase: for
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: scala
|
||||
-
|
||||
for ($1) $0
|
||||
---
|
||||
|
||||
language: cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
for ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: php | c
|
||||
-
|
||||
for ($1; $2; $3) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
forval $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: elixir | lua
|
||||
-
|
||||
for $1 do
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
for $1 in $2 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: go
|
||||
-
|
||||
for $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: r | kotlin
|
||||
-
|
||||
for ($1 in $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
for $1 in $2:
|
||||
$0
|
||||
---
|
||||
|
||||
language: terraform
|
||||
-
|
||||
for $1 in $2 : $0
|
||||
---
|
||||
@@ -0,0 +1,66 @@
|
||||
name: forRangeStatement
|
||||
phrase: for range
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | csharp | java
|
||||
-
|
||||
for (int i = 0; i < $1; ++i) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
for (size_t i = 0; i < $1; ++i) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
for (let i = 0; i < $1; ++i) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
for i in range($1):
|
||||
$0
|
||||
---
|
||||
|
||||
language: scala
|
||||
-
|
||||
for (i <- 0 until $1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: go
|
||||
-
|
||||
for i := 0; i < $1; i++ {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
forval $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
for (${1} in 1:${2}) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
for i in 0..$1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,33 @@
|
||||
name: formatString
|
||||
phrase: format
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
std::format("$0")
|
||||
---
|
||||
|
||||
language: csharp
|
||||
-
|
||||
String.Format("$0")
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
String.format("$0")
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
`$0`
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
f"$0"
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
${1:glue::}glue("$0")
|
||||
---
|
||||
@@ -0,0 +1,16 @@
|
||||
name: functionCall
|
||||
phrase: call
|
||||
insertionScope: statement
|
||||
|
||||
$0.wrapperPhrase: call
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | python | talon | java | javascript | typescript | javascriptreact | typescriptreact | css | scss | sql | r
|
||||
-
|
||||
$1($0)
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
$1 $0
|
||||
---
|
||||
@@ -0,0 +1,75 @@
|
||||
name: functionDeclaration
|
||||
phrase: funk
|
||||
insertionScope: namedFunction | statement
|
||||
|
||||
$0.wrapperPhrase: funk
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
-
|
||||
void $1($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
-
|
||||
function $1($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
def $1($2):
|
||||
$0
|
||||
---
|
||||
|
||||
language: rust
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
fn $1($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: ruby
|
||||
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
def $1($2)
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: vimscript
|
||||
-
|
||||
function $1($2)
|
||||
$0
|
||||
endfunction
|
||||
---
|
||||
|
||||
language: php
|
||||
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
function $1($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: r
|
||||
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
$1 <- function($2){
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,15 @@
|
||||
name: codeQuote
|
||||
phrase: code
|
||||
-
|
||||
```
|
||||
$0
|
||||
```
|
||||
---
|
||||
|
||||
name: codeQuoteLanguage
|
||||
phrase: code lang
|
||||
-
|
||||
```$1
|
||||
$0
|
||||
```
|
||||
---
|
||||
@@ -0,0 +1,14 @@
|
||||
name: goToStatement
|
||||
phrase: go to
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | php
|
||||
-
|
||||
goto $0;
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
goto $0
|
||||
---
|
||||
@@ -0,0 +1,33 @@
|
||||
language: html | javascriptreact | typescriptreact
|
||||
---
|
||||
|
||||
name: attributeClassName
|
||||
phrase: class name
|
||||
-
|
||||
className="$0"
|
||||
---
|
||||
|
||||
name: table
|
||||
phrase: table
|
||||
-
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>$1</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
---
|
||||
|
||||
name: unorderedList
|
||||
phrase: list
|
||||
-
|
||||
<ul>
|
||||
<li>$0</li>
|
||||
</ul>
|
||||
---
|
||||
@@ -0,0 +1,71 @@
|
||||
name: ifElseStatement
|
||||
phrase: if else
|
||||
insertionScope: statement
|
||||
|
||||
$1.wrapperPhrase: if else cond
|
||||
$1.wrapperScope: statement
|
||||
$2.wrapperPhrase: if else
|
||||
$2.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | scala | kotlin | r
|
||||
-
|
||||
if ($1) {
|
||||
$2
|
||||
} else {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
if $1:
|
||||
$2
|
||||
else:
|
||||
$0
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
if $1 then
|
||||
$2
|
||||
else
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
if $1
|
||||
$2
|
||||
else
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: vimscript
|
||||
-
|
||||
if $1
|
||||
$2
|
||||
else
|
||||
$0
|
||||
endif
|
||||
---
|
||||
|
||||
language: rust | stata | go
|
||||
-
|
||||
if $1 {
|
||||
$2
|
||||
} else {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: elixir
|
||||
-
|
||||
if $1 do
|
||||
$2
|
||||
else
|
||||
$0
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,57 @@
|
||||
name: ifStatement
|
||||
phrase: if
|
||||
insertionScope: statement
|
||||
|
||||
$1.wrapperPhrase: if cond
|
||||
$1.wrapperScope: statement
|
||||
$0.wrapperPhrase: if
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | scala | kotlin | r
|
||||
-
|
||||
if ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
if $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
if $1 then
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
if $1
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: vimscript
|
||||
-
|
||||
if $1
|
||||
$0
|
||||
endif
|
||||
---
|
||||
|
||||
language: rust | stata | go
|
||||
-
|
||||
if $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: elixir
|
||||
-
|
||||
if $1 do
|
||||
$0
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,64 @@
|
||||
name: importStatement
|
||||
phrase: import
|
||||
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
import $0 from "$0";
|
||||
---
|
||||
|
||||
language: python | go | scala
|
||||
-
|
||||
import $0
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
local $1 = require('$0')
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
require "$0"
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
import $0;
|
||||
---
|
||||
|
||||
language: php | rust
|
||||
-
|
||||
use $0;
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
library($0)
|
||||
---
|
||||
|
||||
language: stata
|
||||
-
|
||||
ssc install $0
|
||||
---
|
||||
|
||||
language: css | scss
|
||||
-
|
||||
@import $0
|
||||
---
|
||||
|
||||
language: csharp
|
||||
-
|
||||
using $0;
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
library(${1}${2:, warn.conflicts = FALSE})
|
||||
---
|
||||
|
||||
language: c
|
||||
-
|
||||
#include $0
|
||||
---
|
||||
@@ -0,0 +1,23 @@
|
||||
name: importFromStatement
|
||||
phrase: import from
|
||||
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
import $1 from "$0";
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
from $1 import $0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
library(
|
||||
${1},
|
||||
include.only = c(${0})${2:,
|
||||
warn.conflicts = FALSE}
|
||||
)
|
||||
---
|
||||
@@ -0,0 +1,19 @@
|
||||
name: importStarStatement
|
||||
phrase: import star
|
||||
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
import * as $0 from "$0";
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
from $0 import *
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
use $0::*;
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: includeHeaderStatement
|
||||
phrase: include header | include head
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#include "$0.h"
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: includeLocalStatement
|
||||
phrase: include local | include low
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#include "$0"
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: includeSystemStatement
|
||||
phrase: include system | include sys
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#include <$0>
|
||||
---
|
||||
@@ -0,0 +1,11 @@
|
||||
name: infiniteLoopStatement
|
||||
phrase: loop
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
loop {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,19 @@
|
||||
name: item
|
||||
phrase: item
|
||||
insertionScope: collectionItem
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
$1: $0,
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
"$1": $0,
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
${1}="$0",
|
||||
---
|
||||
@@ -0,0 +1,53 @@
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
---
|
||||
|
||||
name: forInLoopStatement
|
||||
phrase: for in
|
||||
insertionScope: statement
|
||||
-
|
||||
for (const $1 in $2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: anonymousFunctionDeclarationAndCall
|
||||
phrase: self calling
|
||||
-
|
||||
(() => {
|
||||
$0
|
||||
})();
|
||||
---
|
||||
|
||||
name: namedLambdaExpression
|
||||
phrase: arrow funk
|
||||
insertionScope: statement
|
||||
-
|
||||
const $1 = ($2) => {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: printTimeStatement
|
||||
phrase: print time
|
||||
insertionScope: statement
|
||||
-
|
||||
console.time("$0");
|
||||
---
|
||||
|
||||
name: constAssignment
|
||||
phrase: const
|
||||
insertionScope: statement
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
-
|
||||
const $1 = $0;
|
||||
---
|
||||
|
||||
name: letAssignment
|
||||
phrase: let
|
||||
insertionScope: statement
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
-
|
||||
let $1 = $0;
|
||||
---
|
||||
@@ -0,0 +1,30 @@
|
||||
language: javascript | javascriptreact | typescriptreact
|
||||
---
|
||||
|
||||
name: attribute
|
||||
-
|
||||
$name={$0}
|
||||
---
|
||||
|
||||
name: reactUseState
|
||||
phrase: use state
|
||||
insertionScope: statement
|
||||
-
|
||||
const [$1, set${1/(.)/${1:/capitalize}/}] = useState($0);
|
||||
---
|
||||
|
||||
name: reactUseRef
|
||||
phrase: use ref
|
||||
insertionScope: statement
|
||||
-
|
||||
const $0 = useRef();
|
||||
---
|
||||
|
||||
name: reactUseEffect
|
||||
phrase: use effect
|
||||
insertionScope: statement
|
||||
-
|
||||
useEffect(() => {
|
||||
$0
|
||||
}, []);
|
||||
---
|
||||
@@ -0,0 +1,38 @@
|
||||
name: lambdaExpression
|
||||
phrase: lambda
|
||||
|
||||
$0.wrapperPhrase: lambda
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: csharp | javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
($1) => {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
($1) -> {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
lambda $1: $0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
function($1){ $0 }
|
||||
---
|
||||
|
||||
|
||||
language: cpp
|
||||
-
|
||||
[$1]($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,28 @@
|
||||
language: lua
|
||||
---
|
||||
|
||||
name: forInIPairs
|
||||
phrase: for eye pairs
|
||||
insertionScope: statement
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
for _, $1 in ipairs($2) do
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
name: forInPairs
|
||||
phrase: for pairs
|
||||
insertionScope: statement
|
||||
-
|
||||
for ${1:k}, ${2:v} in pairs($3) do
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
name: tryCatchStatement
|
||||
phrase: try catch
|
||||
insertionScope: statement
|
||||
-
|
||||
pcall($0)
|
||||
---
|
||||
@@ -0,0 +1,45 @@
|
||||
language: markdown
|
||||
---
|
||||
|
||||
name: link
|
||||
phrase: link
|
||||
-
|
||||
[$1]($0)
|
||||
---
|
||||
|
||||
name: image
|
||||
phrase: image
|
||||
-
|
||||

|
||||
---
|
||||
|
||||
|
||||
name: checkbox
|
||||
phrase: to do | check box | tick box
|
||||
-
|
||||
* [ ] $0
|
||||
---
|
||||
|
||||
name: bold
|
||||
phrase: bold | strong
|
||||
-
|
||||
**$0**
|
||||
---
|
||||
|
||||
name: italic
|
||||
phrase: italic | emph | emphasis
|
||||
-
|
||||
*$0*
|
||||
---
|
||||
|
||||
name: italic bold
|
||||
phrase: italic bold | bold italic | strong emphasis | strong emph
|
||||
-
|
||||
***$0***
|
||||
---
|
||||
|
||||
name: quote
|
||||
phrase: quote
|
||||
-
|
||||
> $0
|
||||
---
|
||||
@@ -0,0 +1,13 @@
|
||||
name: methodDeclaration
|
||||
phrase: method
|
||||
insertionScope: namedFunction | statement
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
-
|
||||
$1($2) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,13 @@
|
||||
name: newInstance
|
||||
phrase: instance
|
||||
---
|
||||
|
||||
language: cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
new $1($0);
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
$1($0)
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
name: preprocessorDefineStatement
|
||||
phrase: pre define | define
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
$0.insertionFormatter: ALL_CAPS,SNAKE_CASE
|
||||
-
|
||||
#define $0
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: preprocessorElseIfStatement
|
||||
phrase: pre elif
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#elif $0
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: preprocessorEndIfStatement
|
||||
phrase: pre end if | end if
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#endif $0
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: preprocessorErrorStatement
|
||||
phrase: pre error | error
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#error $0
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
name: preprocessorIfDefineStatement
|
||||
phrase: pre if deaf | if deaf
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
$0.insertionFormatter: ALL_CAPS,SNAKE_CASE
|
||||
-
|
||||
#ifdef $0
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
name: preprocessorIfStatement
|
||||
phrase: pre if
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
-
|
||||
#if $0
|
||||
---
|
||||
@@ -0,0 +1,10 @@
|
||||
name: preprocessorUndefineStatement
|
||||
phrase: pre undeaf | undeaf
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp
|
||||
$0.insertionFormatter: ALL_CAPS,SNAKE_CASE
|
||||
-
|
||||
#undef $0
|
||||
---
|
||||
@@ -0,0 +1,36 @@
|
||||
name: printStatement
|
||||
phrase: print
|
||||
insertionScope: statement
|
||||
|
||||
$0.wrapperPhrase: print
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
std::printf($0);
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
System.out.println($0);
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
console.log($0);
|
||||
---
|
||||
|
||||
language: python | talon | r
|
||||
-
|
||||
print($0)
|
||||
---
|
||||
|
||||
language: csharp
|
||||
-
|
||||
Console.WriteLine($0);
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
println!($0);
|
||||
---
|
||||
@@ -0,0 +1,96 @@
|
||||
language: python
|
||||
---
|
||||
|
||||
name: talonModuleDeclaration
|
||||
phrase: module
|
||||
insertionScope: statement
|
||||
-
|
||||
mod = Module()
|
||||
---
|
||||
|
||||
name: talonContextDeclaration
|
||||
phrase: context
|
||||
insertionScope: statement
|
||||
-
|
||||
ctx = Context()
|
||||
---
|
||||
|
||||
name: talonAppDeclaration
|
||||
phrase: module app
|
||||
insertionScope: statement
|
||||
-
|
||||
mod.apps.$1 = r"""
|
||||
$0
|
||||
"""
|
||||
---
|
||||
|
||||
name: talonModuleClass
|
||||
phrase: module class
|
||||
insertionScope: class | statement
|
||||
-
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
$0
|
||||
---
|
||||
|
||||
name: talonContextMatch
|
||||
phrase: context match
|
||||
insertionScope: statement
|
||||
-
|
||||
ctx.matches = r"""
|
||||
$0
|
||||
"""
|
||||
---
|
||||
|
||||
name: talonContextList
|
||||
phrase: context list
|
||||
insertionScope: statement
|
||||
-
|
||||
ctx.lists["user.$1"] = {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: talonContextClass
|
||||
phrase: context class
|
||||
insertionScope: class | statement
|
||||
-
|
||||
@ctx.action_class("$1")
|
||||
class $2Actions:
|
||||
$0
|
||||
---
|
||||
|
||||
name: suppressError
|
||||
phrase: suppress error
|
||||
-
|
||||
with suppress(AttributeError):
|
||||
$0
|
||||
---
|
||||
|
||||
name: listComprehension
|
||||
phrase: list comp
|
||||
insertionScope: statement
|
||||
-
|
||||
[$2 for $2 in $1 if $0]
|
||||
---
|
||||
|
||||
name: setComprehension
|
||||
phrase: set comp
|
||||
insertionScope: statement
|
||||
-
|
||||
{$0 for $0 in $1}
|
||||
---
|
||||
|
||||
name: dictComprehension
|
||||
phrase: dict comp
|
||||
insertionScope: statement
|
||||
-
|
||||
{$0: $2 for $2 in $1}
|
||||
---
|
||||
|
||||
name: generatorExpression
|
||||
phrase: gen comp
|
||||
insertionScope: statement
|
||||
-
|
||||
($2 for $2 in $1 if $0)
|
||||
---
|
||||
@@ -0,0 +1,19 @@
|
||||
name: returnStatement
|
||||
phrase: return
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | rust
|
||||
-
|
||||
return $0;
|
||||
---
|
||||
|
||||
language: python | go | kotlin | lua | ruby | scala
|
||||
-
|
||||
return $0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
return($0)
|
||||
---
|
||||
@@ -0,0 +1,104 @@
|
||||
language: rust
|
||||
---
|
||||
|
||||
name: implementsStruct
|
||||
phrase: imp | implement
|
||||
insertionScope: statement
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
impl $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: implementsGenericStruct
|
||||
phrase: generic imp | generic implement | gen imp | gen implement
|
||||
insertionScope: statement
|
||||
|
||||
$2.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
impl<$1> $2<$3> {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: enumTypeDeclaration
|
||||
phrase: enum
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
enum $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: traitDeclaration
|
||||
phrase: trait
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
trait $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: traitImplementation
|
||||
phrase: implement trait | imp trait
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
impl $1 for $2 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: ifLetStatement
|
||||
phrase: if let
|
||||
insertionScope: statement
|
||||
-
|
||||
if let $1 = $2 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: letElseStatement
|
||||
phrase: let else
|
||||
insertionScope: statement
|
||||
-
|
||||
let $1 = $2 else {
|
||||
return $0;
|
||||
};
|
||||
---
|
||||
|
||||
name: unsafeBlock
|
||||
phrase: unsafe
|
||||
-
|
||||
unsafe {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: attributeStatement
|
||||
phrase: attribute | attr
|
||||
$0.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
#[$0]
|
||||
---
|
||||
|
||||
name: moduleDeclaration
|
||||
phrase: mod | module
|
||||
$1.insertionFormatter: SNAKE_CASE
|
||||
-
|
||||
mod $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
name: testModuleDeclaration
|
||||
phrase: test mod | test module
|
||||
-
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,11 @@
|
||||
language: shellscript
|
||||
---
|
||||
|
||||
name: shebang
|
||||
phrase: shebang
|
||||
-
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
$0
|
||||
---
|
||||
@@ -0,0 +1,20 @@
|
||||
language: sql
|
||||
---
|
||||
|
||||
name: createTable
|
||||
phrase: create table
|
||||
insertionScope: statement
|
||||
-
|
||||
CREATE TABLE $1(
|
||||
$0
|
||||
);
|
||||
---
|
||||
|
||||
name: withStatement
|
||||
phrase: with
|
||||
insertionScope: statement
|
||||
-
|
||||
WITH $1 AS (
|
||||
SELECT $0
|
||||
)
|
||||
---
|
||||
@@ -0,0 +1,19 @@
|
||||
name: structDeclaration
|
||||
phrase: struct
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
---
|
||||
|
||||
language: rust
|
||||
insertionScope: class
|
||||
-
|
||||
struct $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: cpp
|
||||
insertionScope: statement
|
||||
-
|
||||
struct $1 {
|
||||
$0
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
name: switchStatement
|
||||
phrase: switch
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php
|
||||
-
|
||||
switch ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
match $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
match $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: kotlin
|
||||
-
|
||||
when ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
case $1
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: scala
|
||||
-
|
||||
$1 match {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: go
|
||||
-
|
||||
switch $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: elixir
|
||||
-
|
||||
case $1 do
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
case_when(
|
||||
$0
|
||||
.default = ${1}
|
||||
)
|
||||
---
|
||||
@@ -0,0 +1,11 @@
|
||||
language: talon
|
||||
---
|
||||
|
||||
name: voiceCommandDeclaration
|
||||
phrase: command
|
||||
insertionScope: command
|
||||
|
||||
$0.insertionFormatter: NOOP
|
||||
-
|
||||
$0: user.run_rpc_command("$CLIPBOARD")
|
||||
---
|
||||
@@ -0,0 +1,33 @@
|
||||
name: ternary
|
||||
phrase: ternary
|
||||
---
|
||||
|
||||
language: c | cpp | java | csharp | javascript | typescript | javascriptreact | typescriptreact | terraform | ruby
|
||||
-
|
||||
$1 ? $2 : $0
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
$1 if $2 else $0
|
||||
---
|
||||
|
||||
language: lua
|
||||
-
|
||||
$1 and $2 or $0
|
||||
---
|
||||
|
||||
language: rust
|
||||
-
|
||||
if $1 { $2 } else { $0 }
|
||||
---
|
||||
|
||||
language: scala | kotlin
|
||||
-
|
||||
if ($1) $2 else $0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
if ($2) { $1 } else { $0 }
|
||||
---
|
||||
@@ -0,0 +1,33 @@
|
||||
name: throwException
|
||||
phrase: exception
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
throw std::runtime_error("$0");
|
||||
---
|
||||
|
||||
language: java
|
||||
-
|
||||
throw new Exception(String.format("$0"));
|
||||
---
|
||||
|
||||
language: csharp
|
||||
-
|
||||
throw new Exception(String.Format("$0"));
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
throw Error(`$0`);
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
raise ValueError(f"$0")
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
stop($0)
|
||||
---
|
||||
@@ -0,0 +1,60 @@
|
||||
name: tryCatchStatement
|
||||
phrase: try catch
|
||||
insertionScope: statement
|
||||
|
||||
$1.wrapperPhrase: try
|
||||
$1.wrapperScope: statement
|
||||
$0.wrapperPhrase: catch
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: cpp
|
||||
-
|
||||
try {
|
||||
$1
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: csharp | java
|
||||
-
|
||||
try {
|
||||
$1
|
||||
}
|
||||
catch(final Exception ex) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: javascript | typescript | javascriptreact | typescriptreact
|
||||
-
|
||||
try {
|
||||
$1
|
||||
}
|
||||
catch(error) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
try:
|
||||
$1
|
||||
except Exception as ex:
|
||||
$0
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
tryCatch({
|
||||
$0
|
||||
}, warning = function(w) {
|
||||
$1
|
||||
}, error = function(e) {
|
||||
$2
|
||||
}, finally = {
|
||||
$3
|
||||
})
|
||||
---
|
||||
@@ -0,0 +1,31 @@
|
||||
name: tryStatement
|
||||
phrase: try
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php
|
||||
-
|
||||
try {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
try:
|
||||
$0
|
||||
---
|
||||
|
||||
language: elixir
|
||||
-
|
||||
try do
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: r
|
||||
-
|
||||
tryCatch({
|
||||
$0
|
||||
},
|
||||
---
|
||||
@@ -0,0 +1,13 @@
|
||||
language: typescript | typescriptreact
|
||||
---
|
||||
|
||||
name: interfaceDeclaration
|
||||
phrase: interface
|
||||
insertionScope: statement
|
||||
|
||||
$1.insertionFormatter: PUBLIC_CAMEL_CASE
|
||||
-
|
||||
interface $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
@@ -0,0 +1,11 @@
|
||||
name: unlessStatement
|
||||
phrase: unless
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
unless $1
|
||||
$0
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,11 @@
|
||||
name: untilLoopStatement
|
||||
phrase: until
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
until $1
|
||||
$0
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,45 @@
|
||||
name: whileLoopStatement
|
||||
phrase: while
|
||||
insertionScope: statement
|
||||
---
|
||||
|
||||
language: c | cpp | csharp | java | javascript | typescript | javascriptreact | typescriptreact | php | scala | kotlin | r
|
||||
-
|
||||
while ($1) {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
while $1:
|
||||
$0
|
||||
---
|
||||
|
||||
language: ruby
|
||||
-
|
||||
while $1
|
||||
$0
|
||||
end
|
||||
---
|
||||
|
||||
language: go
|
||||
-
|
||||
for $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: rust | stata
|
||||
-
|
||||
while $1 {
|
||||
$0
|
||||
}
|
||||
---
|
||||
|
||||
language: elixir | lua
|
||||
-
|
||||
while $1 do
|
||||
$0
|
||||
end
|
||||
---
|
||||
@@ -0,0 +1,13 @@
|
||||
name: withStatement
|
||||
phrase: with
|
||||
insertionScope: statement
|
||||
|
||||
$0.wrapperPhrase: with
|
||||
$0.wrapperScope: statement
|
||||
---
|
||||
|
||||
language: python
|
||||
-
|
||||
with $1:
|
||||
$0
|
||||
---
|
||||
@@ -0,0 +1,23 @@
|
||||
language: xml | html | javascriptreact | typescriptreact
|
||||
---
|
||||
|
||||
name: element
|
||||
phrase: element | tag
|
||||
insertionScope: xmlElement
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
$0.wrapperPhrase: element | tag
|
||||
$0.wrapperScope: xmlElement
|
||||
-
|
||||
<$1>
|
||||
$0
|
||||
</$1>
|
||||
---
|
||||
|
||||
name: attribute
|
||||
phrase: attribute
|
||||
|
||||
$1.insertionFormatter: PRIVATE_CAMEL_CASE
|
||||
-
|
||||
$1=$0
|
||||
---
|
||||
@@ -0,0 +1,56 @@
|
||||
import re
|
||||
|
||||
from talon import Module, actions
|
||||
|
||||
from .snippet_types import Snippet
|
||||
from .snippets_insert_raw_text import go_to_next_stop_raw, insert_snippet_raw_text
|
||||
|
||||
mod = Module()
|
||||
|
||||
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
def insert_snippet(body: str):
|
||||
"""Insert snippet"""
|
||||
insert_snippet_raw_text(body)
|
||||
|
||||
def move_cursor_to_next_snippet_stop():
|
||||
"""Moves the cursor to the next snippet stop"""
|
||||
go_to_next_stop_raw()
|
||||
|
||||
def insert_snippet_by_name(
|
||||
name: str,
|
||||
substitutions: dict[str, str] = None,
|
||||
):
|
||||
"""Insert snippet <name>"""
|
||||
snippet: Snippet = actions.user.get_snippet(name)
|
||||
body = snippet.body
|
||||
|
||||
if substitutions:
|
||||
for k, v in substitutions.items():
|
||||
reg = re.compile(rf"\${k}|\$\{{{k}\}}")
|
||||
if not reg.search(body):
|
||||
raise ValueError(
|
||||
f"Can't substitute non existing variable '{k}' in snippet '{name}'"
|
||||
)
|
||||
body = reg.sub(v, body)
|
||||
|
||||
actions.user.insert_snippet(body)
|
||||
|
||||
def insert_snippet_by_name_with_phrase(name: str, phrase: str):
|
||||
"""Insert snippet <name> with phrase <phrase>"""
|
||||
snippet: Snippet = actions.user.get_snippet(name)
|
||||
substitutions = {}
|
||||
|
||||
for variable in snippet.variables:
|
||||
if variable.insertion_formatters is not None:
|
||||
formatters = ",".join(variable.insertion_formatters)
|
||||
formatted_phrase = actions.user.formatted_text(phrase, formatters)
|
||||
substitutions[variable.name] = formatted_phrase
|
||||
|
||||
if not substitutions:
|
||||
raise ValueError(
|
||||
f"Can't use snippet phrase. No variable with insertion formatter in snippet '{name}'"
|
||||
)
|
||||
|
||||
actions.user.insert_snippet_by_name(name, substitutions)
|
||||
@@ -0,0 +1,219 @@
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
from talon import Module, actions, app, settings
|
||||
|
||||
mod = Module()
|
||||
|
||||
|
||||
mod.setting(
|
||||
"snippet_raw_text_spaces_per_tab",
|
||||
type=int,
|
||||
default=4,
|
||||
desc="""The number of spaces per tab when inserting snippets as raw text. Set to -1 to insert tabs as tabs, such as in code editors that can expand tabs in pasted or typed text. This setting is provided for applications like web browsers and chat apps.""",
|
||||
)
|
||||
|
||||
mod.setting(
|
||||
"snippet_raw_text_paste",
|
||||
type=bool,
|
||||
default=False,
|
||||
desc="""If true, inserting snippets as raw text will always be done through pasting""",
|
||||
)
|
||||
|
||||
RE_STOP = re.compile(r"\$(\d+|\w+)|\$\{(\d+|\w+)\}|\$\{(\d+|\w+):(.+)\}")
|
||||
LAST_SNIPPET_HOLE_KEY_VALUE = 1000
|
||||
|
||||
|
||||
@dataclass
|
||||
class Stop:
|
||||
name: str
|
||||
rows_up: int
|
||||
columns_left: int
|
||||
row: int
|
||||
col: int
|
||||
|
||||
def compute_sorting_key(self) -> int:
|
||||
"""Returns a key value used to sort stops"""
|
||||
if self.name == "0":
|
||||
return LAST_SNIPPET_HOLE_KEY_VALUE
|
||||
if self.name.isdigit():
|
||||
return int(self.name)
|
||||
return 999
|
||||
|
||||
|
||||
stop_stack: list[Stop] = []
|
||||
|
||||
|
||||
def go_to_next_stop_raw():
|
||||
"""Goes to the next snippet stop if it exists"""
|
||||
global stop_stack
|
||||
if len(stop_stack) > 1:
|
||||
current_stop = stop_stack.pop()
|
||||
next_stop = stop_stack[-1]
|
||||
move_to_correct_row(current_stop, next_stop)
|
||||
move_to_correct_column(next_stop)
|
||||
else:
|
||||
stop_stack = []
|
||||
|
||||
|
||||
def insert_snippet_raw_text(body: str):
|
||||
"""Insert snippet as raw text without editor support"""
|
||||
updated_snippet, stops = parse_snippet(body)
|
||||
sorted_stops = compute_stops_sorted_always_moving_left_to_right(stops)
|
||||
stop = get_first_stop(sorted_stops)
|
||||
|
||||
update_stop_information(sorted_stops)
|
||||
|
||||
if settings.get("user.snippet_raw_text_paste"):
|
||||
actions.user.paste(updated_snippet)
|
||||
else:
|
||||
actions.insert(updated_snippet)
|
||||
|
||||
if stop:
|
||||
up(stop.rows_up)
|
||||
move_to_correct_column(stop)
|
||||
|
||||
|
||||
def update_stop_information(stops: list[Stop]):
|
||||
global stop_stack
|
||||
if len(stops) > 1:
|
||||
stop_stack = stops[:]
|
||||
stop_stack.reverse()
|
||||
else:
|
||||
stop_stack = []
|
||||
|
||||
|
||||
def compute_stops_sorted_always_moving_left_to_right(stops: list[Stop]) -> list[Stop]:
|
||||
"""Without editor support, moving from right to left is problematic. Each line of stops is sorted by the smallest snippet hole key in the line. Each line gets sorted from left to right."""
|
||||
# Separate the stops by line keeping track of the smallest key in each line
|
||||
lines = defaultdict(list)
|
||||
smallest_keys = defaultdict(lambda: LAST_SNIPPET_HOLE_KEY_VALUE)
|
||||
for stop in stops:
|
||||
lines[stop.row].append(stop)
|
||||
line_key = smallest_keys[stop.row]
|
||||
smallest_keys[stop.row] = min(line_key, stop.compute_sorting_key())
|
||||
|
||||
# If a line was from right to left, notify user and sort
|
||||
if is_any_line_from_right_to_left(lines.values()):
|
||||
app.notify(
|
||||
"The snippet you inserted got adjusted to move from left to right because editor support is unavailable."
|
||||
)
|
||||
sorted_stops: list[Stop] = []
|
||||
# Sort lines by key
|
||||
sorted_lines = sorted(
|
||||
lines.values(), key=lambda line: smallest_keys[line[0].row]
|
||||
)
|
||||
# Add every line sorted from left to right
|
||||
for line in sorted_lines:
|
||||
sorted_line = sorted(line, key=lambda stop: stop.col)
|
||||
sorted_stops.extend(sorted_line)
|
||||
return sorted_stops
|
||||
return sorted(stops, key=lambda stop: stop.compute_sorting_key())
|
||||
|
||||
|
||||
def is_any_line_from_right_to_left(lines) -> bool:
|
||||
for line in lines:
|
||||
# Lines with only one stop are always in order
|
||||
if len(line) > 1:
|
||||
stop = line[0]
|
||||
stop_key = stop.compute_sorting_key()
|
||||
for next_stop in line[1:]:
|
||||
next_key = next_stop.compute_sorting_key()
|
||||
# If the ordering between the keys and columns are inconsistent,
|
||||
# the stops on this line go from right to left
|
||||
if (next_key < stop_key) != (next_stop.col < stop.col):
|
||||
return True
|
||||
stop_key = next_key
|
||||
stop = next_stop
|
||||
return False
|
||||
|
||||
|
||||
def move_to_correct_column(stop: Stop):
|
||||
actions.edit.line_end()
|
||||
move_cursor_left(stop.columns_left)
|
||||
|
||||
|
||||
def move_to_correct_row(current_stop: Stop, next_stop: Stop):
|
||||
start = current_stop.row
|
||||
end = next_stop.row
|
||||
if start < end:
|
||||
for _ in range(end - start):
|
||||
actions.edit.down()
|
||||
elif start > end:
|
||||
for _ in range(start - end):
|
||||
actions.edit.up()
|
||||
|
||||
|
||||
def format_tabs(text: str) -> str:
|
||||
"""Possibly replaces tabs with spaces in the given text."""
|
||||
spaces_per_tab: int = settings.get("user.snippet_raw_text_spaces_per_tab")
|
||||
if spaces_per_tab < 0:
|
||||
return text
|
||||
return re.sub(r"\t", " " * spaces_per_tab, text)
|
||||
|
||||
|
||||
def parse_snippet(body: str):
|
||||
# Some IM services will send the message on a tab
|
||||
body = format_tabs(body)
|
||||
|
||||
# Replace variable with appropriate value/text
|
||||
body = re.sub(r"\$TM_SELECTED_TEXT", lambda _: actions.edit.selected_text(), body)
|
||||
body = re.sub(r"\$CLIPBOARD", lambda _: actions.clip.text(), body)
|
||||
|
||||
lines = body.splitlines()
|
||||
stops: list[Stop] = []
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
match = RE_STOP.search(line)
|
||||
|
||||
while match:
|
||||
stops.append(
|
||||
Stop(
|
||||
name=match.group(1) or match.group(2) or match.group(3),
|
||||
rows_up=len(lines) - i - 1,
|
||||
columns_left=0,
|
||||
row=i,
|
||||
col=match.start(),
|
||||
)
|
||||
)
|
||||
|
||||
# Remove tab stops and variables.
|
||||
stop_text = match.group(0)
|
||||
default_value = match.group(4) or ""
|
||||
line = line.replace(stop_text, default_value, 1)
|
||||
|
||||
# Might have multiple stops on the same line
|
||||
match = RE_STOP.search(line)
|
||||
|
||||
# Update existing line
|
||||
lines[i] = line
|
||||
|
||||
# Can't calculate column left until line text is fully updated
|
||||
for stop in stops:
|
||||
stop.columns_left = len(lines[stop.row]) - stop.col
|
||||
|
||||
updated_snippet = "\n".join(lines)
|
||||
|
||||
return updated_snippet, stops
|
||||
|
||||
|
||||
def up(n: int):
|
||||
"""Move cursor up <n> rows"""
|
||||
for _ in range(n):
|
||||
actions.edit.up()
|
||||
|
||||
|
||||
def move_cursor_left(n: int):
|
||||
"""Move cursor left <n> columns"""
|
||||
for _ in range(n):
|
||||
actions.edit.left()
|
||||
|
||||
|
||||
def get_first_stop(stops: list[Stop]):
|
||||
if not stops:
|
||||
return None
|
||||
stop = stops[0]
|
||||
if stop.rows_up == 0 and stop.columns_left == 0:
|
||||
return None
|
||||
return stop
|
||||
@@ -0,0 +1,451 @@
|
||||
import logging
|
||||
import re
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from typing import Callable, Union
|
||||
|
||||
from .snippet_types import Snippet, SnippetVariable
|
||||
|
||||
|
||||
class SnippetDocument:
|
||||
file: str
|
||||
line_doc: int
|
||||
line_body: int
|
||||
variables: list[SnippetVariable] = []
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
phrases: list[str] | None = None
|
||||
insertionScopes: list[str] | None = None
|
||||
languages: list[str] | None = None
|
||||
body: str | None = None
|
||||
|
||||
def __init__(self, file: str, line_doc: int, line_body: int):
|
||||
self.file = file
|
||||
self.line_doc = line_doc
|
||||
self.line_body = line_body
|
||||
|
||||
|
||||
def create_snippets_from_file(file: Path) -> list[Snippet]:
|
||||
documents = parse_file(file)
|
||||
return create_snippets(documents)
|
||||
|
||||
|
||||
def create_snippets(documents: list[SnippetDocument]) -> list[Snippet]:
|
||||
if len(documents) == 0:
|
||||
return []
|
||||
|
||||
if documents[0].body is None:
|
||||
default_context = documents[0]
|
||||
documents = documents[1:]
|
||||
else:
|
||||
default_context = SnippetDocument("", -1, -1)
|
||||
|
||||
snippets: list[Snippet] = []
|
||||
|
||||
for doc in documents:
|
||||
snippet = create_snippet(doc, default_context)
|
||||
if snippet:
|
||||
snippets.append(snippet)
|
||||
|
||||
return snippets
|
||||
|
||||
|
||||
def create_snippet(
|
||||
document: SnippetDocument,
|
||||
default_context: SnippetDocument,
|
||||
) -> Snippet | None:
|
||||
body = normalize_snippet_body_tabs(document.body)
|
||||
variables = combine_variables(default_context.variables, document.variables)
|
||||
body, variables = add_final_stop_to_snippet_body(body, variables)
|
||||
|
||||
snippet = Snippet(
|
||||
name=document.name or default_context.name or "",
|
||||
description=document.description or default_context.description,
|
||||
languages=document.languages or default_context.languages,
|
||||
phrases=document.phrases or default_context.phrases,
|
||||
insertion_scopes=document.insertionScopes or default_context.insertionScopes,
|
||||
variables=variables,
|
||||
body=body,
|
||||
)
|
||||
|
||||
if not validate_snippet(document, snippet):
|
||||
return None
|
||||
|
||||
return snippet
|
||||
|
||||
|
||||
def validate_snippet(document: SnippetDocument, snippet: Snippet) -> bool:
|
||||
is_valid = True
|
||||
|
||||
if not snippet.name:
|
||||
error(document.file, document.line_doc, "Missing snippet name")
|
||||
is_valid = False
|
||||
|
||||
if snippet.variables is None:
|
||||
error(document.file, document.line_doc, "Missing snippet variables")
|
||||
return False
|
||||
|
||||
for variable in snippet.variables:
|
||||
var_name = f"${variable.name}"
|
||||
if not is_variable_in_body(variable.name, snippet.body):
|
||||
error(
|
||||
document.file,
|
||||
document.line_body,
|
||||
f"Variable '{var_name}' missing in body '{snippet.body}'",
|
||||
)
|
||||
is_valid = False
|
||||
|
||||
if variable.insertion_formatters is not None and snippet.phrases is None:
|
||||
error(
|
||||
document.file,
|
||||
document.line_doc,
|
||||
f"Snippet phrase required when using '{var_name}.insertionFormatter'",
|
||||
)
|
||||
is_valid = False
|
||||
|
||||
if variable.wrapper_scope is not None and variable.wrapper_phrases is None:
|
||||
error(
|
||||
document.file,
|
||||
document.line_doc,
|
||||
f"'{var_name}.wrapperPhrase' required when using '{var_name}.wrapperScope'",
|
||||
)
|
||||
is_valid = False
|
||||
|
||||
return is_valid
|
||||
|
||||
|
||||
def is_variable_in_body(variable_name: str, body: str) -> bool:
|
||||
return (
|
||||
re.search(create_variable_regular_expression(variable_name), body) is not None
|
||||
)
|
||||
|
||||
|
||||
def create_variable_regular_expression(variable_name: str) -> str:
|
||||
# $value or ${value} or ${value:default}
|
||||
# *? is used to find the smallest possible match.
|
||||
# This stops multiple stops from being treated as a single stop.
|
||||
return rf"\${variable_name}|\${{{variable_name}.*?}}"
|
||||
|
||||
|
||||
def combine_variables(
|
||||
default_variables: list[SnippetVariable],
|
||||
document_variables: list[SnippetVariable],
|
||||
) -> list[SnippetVariable]:
|
||||
variables: dict[str, SnippetVariable] = {}
|
||||
|
||||
for variable in [*default_variables, *document_variables]:
|
||||
if variable.name not in variables:
|
||||
variables[variable.name] = SnippetVariable(variable.name)
|
||||
|
||||
new_variable = variables[variable.name]
|
||||
|
||||
if variable.insertion_formatters is not None:
|
||||
new_variable.insertion_formatters = variable.insertion_formatters
|
||||
|
||||
if variable.wrapper_phrases is not None:
|
||||
new_variable.wrapper_phrases = variable.wrapper_phrases
|
||||
|
||||
if variable.wrapper_scope is not None:
|
||||
new_variable.wrapper_scope = variable.wrapper_scope
|
||||
|
||||
return list(variables.values())
|
||||
|
||||
|
||||
def add_final_stop_to_snippet_body(
|
||||
body: str, variables: list[SnippetVariable]
|
||||
) -> tuple[str, list[SnippetVariable]]:
|
||||
"""Make the snippet body end with stop $0 to allow exiting the snippet with `snip next`.
|
||||
If the snippet has a stop named `0`, it will get replaced with the largest number of a snippet variable name
|
||||
plus 1 with the original variable metadata for stop `0` now associated with the replacement.
|
||||
"""
|
||||
if body:
|
||||
final_stop_matches = find_variable_matches("0", body)
|
||||
|
||||
# Only make a change if the snippet body does not end with a final stop.
|
||||
if not (
|
||||
len(final_stop_matches) > 0 and final_stop_matches[-1].end() == len(body)
|
||||
):
|
||||
biggest_variable_number: int | None = find_largest_variable_number(body)
|
||||
if biggest_variable_number is not None:
|
||||
replacement_name = str(biggest_variable_number + 1)
|
||||
body = replace_final_stop(body, replacement_name, final_stop_matches)
|
||||
variables = replace_variables_for_final_stop(
|
||||
variables, replacement_name
|
||||
)
|
||||
body += "$0"
|
||||
|
||||
return body, variables
|
||||
|
||||
|
||||
def replace_final_stop(body: str, replacement_name: str, final_stop_matches) -> str:
|
||||
# Dealing with matches in reverse means replacing a match
|
||||
# does not change the location of the remaining matches.
|
||||
for match in reversed(final_stop_matches):
|
||||
replacement = match.group().replace("0", replacement_name, 1)
|
||||
body = body[: match.start()] + replacement + body[match.end() :]
|
||||
return body
|
||||
|
||||
|
||||
def replace_variables_for_final_stop(variables, replacement_name: str):
|
||||
variables_clone = deepcopy(variables)
|
||||
for variable in variables_clone:
|
||||
if variable.name == "0":
|
||||
variable.name = replacement_name
|
||||
return variables_clone
|
||||
|
||||
|
||||
def find_variable_matches(variable_name: str, body: str) -> list[re.Match[str]]:
|
||||
"""Find every match of a variable in the body"""
|
||||
expression = create_variable_regular_expression(variable_name)
|
||||
matches = [m for m in re.finditer(expression, body)]
|
||||
return matches
|
||||
|
||||
|
||||
def find_largest_variable_number(body: str) -> int | None:
|
||||
# Find all snippet stops with a numeric variable name
|
||||
# +? is used to find the smallest possible match.
|
||||
# We need this here to avoid treating multiple stops as a single one
|
||||
regular_expression = rf"\$\d+?|\${{\d+?:.*?}}|\${{\d+?}}"
|
||||
matches = re.findall(regular_expression, body)
|
||||
if matches:
|
||||
numbers = [
|
||||
compute_first_integer_in_string(match)
|
||||
for match in matches
|
||||
if match is not None
|
||||
]
|
||||
if numbers:
|
||||
return max(numbers)
|
||||
return None
|
||||
|
||||
|
||||
def compute_first_integer_in_string(text: str) -> int | None:
|
||||
start_index: int | None = None
|
||||
ending_index: int | None = None
|
||||
for i, char in enumerate(text):
|
||||
if char.isdigit():
|
||||
if start_index is None:
|
||||
start_index = i
|
||||
ending_index = i + 1
|
||||
elif start_index is not None:
|
||||
break
|
||||
if start_index is not None:
|
||||
integer_text = text[start_index:ending_index]
|
||||
return int(integer_text)
|
||||
return None
|
||||
|
||||
|
||||
def normalize_snippet_body_tabs(body: str | None) -> str:
|
||||
if not body:
|
||||
return ""
|
||||
|
||||
# If snippet body already contains tabs. No change.
|
||||
if "\t" in body:
|
||||
return body
|
||||
|
||||
lines = []
|
||||
smallest_indentation = None
|
||||
|
||||
for line in body.splitlines():
|
||||
match = re.search(r"^\s+", line)
|
||||
indentation = match.group() if match is not None else ""
|
||||
|
||||
# Keep track of smallest non-empty indentation
|
||||
if len(indentation) > 0 and (
|
||||
smallest_indentation is None or len(indentation) < len(smallest_indentation)
|
||||
):
|
||||
smallest_indentation = indentation
|
||||
|
||||
lines.append({"indentation": indentation, "rest": line[len(indentation) :]})
|
||||
|
||||
# No indentation found in snippet body. No change.
|
||||
if smallest_indentation is None:
|
||||
return body
|
||||
|
||||
normalized_lines = [
|
||||
reconstruct_line(smallest_indentation, line["indentation"], line["rest"])
|
||||
for line in lines
|
||||
]
|
||||
|
||||
return "\n".join(normalized_lines)
|
||||
|
||||
|
||||
def reconstruct_line(smallest_indentation: str, indentation: str, rest: str) -> str:
|
||||
# Update indentation by replacing each occurrent of smallest space indentation with a tab
|
||||
indentation = indentation.replace(smallest_indentation, "\t")
|
||||
return f"{indentation}{rest}"
|
||||
|
||||
|
||||
# ---------- Snippet file parser ----------
|
||||
|
||||
|
||||
def parse_file(file: Path) -> list[SnippetDocument]:
|
||||
with open(file, encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
return parse_file_content(file.name, content)
|
||||
|
||||
|
||||
def parse_file_content(file: str, text: str) -> list[SnippetDocument]:
|
||||
doc_texts = re.split(r"^---\n?$", text, flags=re.MULTILINE)
|
||||
documents: list[SnippetDocument] = []
|
||||
line = 0
|
||||
|
||||
for i, doc_text in enumerate(doc_texts):
|
||||
optional_body = i == 0 and len(doc_texts) > 1
|
||||
document = parse_document(file, line, optional_body, doc_text)
|
||||
if document is not None:
|
||||
documents.append(document)
|
||||
line += doc_text.count("\n") + 1
|
||||
|
||||
return documents
|
||||
|
||||
|
||||
def parse_document(
|
||||
file: str,
|
||||
line: int,
|
||||
optional_body: bool,
|
||||
text: str,
|
||||
) -> Union[SnippetDocument, None]:
|
||||
parts = re.split(r"^-$", text, maxsplit=1, flags=re.MULTILINE)
|
||||
line_body = line + parts[0].count("\n") + 1
|
||||
org_doc = SnippetDocument(file, line, line_body)
|
||||
document = parse_context(file, line, org_doc, parts[0])
|
||||
|
||||
if len(parts) == 2:
|
||||
body = parse_body(parts[1])
|
||||
if body is not None:
|
||||
if document is None:
|
||||
document = org_doc
|
||||
document.body = body
|
||||
|
||||
if document and not document.body and not optional_body:
|
||||
error(file, line, f"Missing body in snippet document '{text}'")
|
||||
return None
|
||||
|
||||
return document
|
||||
|
||||
|
||||
def parse_context(
|
||||
file: str,
|
||||
line: int,
|
||||
document: SnippetDocument,
|
||||
text: str,
|
||||
) -> Union[SnippetDocument, None]:
|
||||
lines = [l.strip() for l in text.splitlines()]
|
||||
keys: set[str] = set()
|
||||
variables: dict[str, SnippetVariable] = {}
|
||||
|
||||
def get_variable(name: str) -> SnippetVariable:
|
||||
if name not in variables:
|
||||
variables[name] = SnippetVariable(name)
|
||||
return variables[name]
|
||||
|
||||
for i, line_text in enumerate(lines):
|
||||
if line_text:
|
||||
parse_context_line(
|
||||
file,
|
||||
line + i,
|
||||
document,
|
||||
keys,
|
||||
get_variable,
|
||||
line_text,
|
||||
)
|
||||
|
||||
if len(keys) == 0:
|
||||
return None
|
||||
|
||||
document.variables = list(variables.values())
|
||||
|
||||
return document
|
||||
|
||||
|
||||
def parse_context_line(
|
||||
file: str,
|
||||
line: int,
|
||||
document: SnippetDocument,
|
||||
keys: set[str],
|
||||
get_variable: Callable[[str], SnippetVariable],
|
||||
text: str,
|
||||
):
|
||||
parts = text.split(":")
|
||||
|
||||
if len(parts) != 2:
|
||||
error(file, line, f"Invalid line '{text}'")
|
||||
return
|
||||
|
||||
key = parts[0].strip()
|
||||
value = parts[1].strip()
|
||||
|
||||
if not key or not value:
|
||||
error(file, line, f"Invalid line '{text}'")
|
||||
return
|
||||
|
||||
if key in keys:
|
||||
warn(file, line, f"Duplicate key '{key}'")
|
||||
|
||||
keys.add(key)
|
||||
|
||||
match key:
|
||||
case "name":
|
||||
document.name = value
|
||||
case "description":
|
||||
document.description = value
|
||||
case "phrase":
|
||||
document.phrases = parse_vector_value(value)
|
||||
case "insertionScope":
|
||||
document.insertionScopes = parse_vector_value(value)
|
||||
case "language":
|
||||
document.languages = parse_vector_value(value)
|
||||
case _:
|
||||
if key.startswith("$"):
|
||||
parse_variable(file, line, get_variable, key, value)
|
||||
else:
|
||||
warn(file, line, f"Unknown key '{key}'")
|
||||
|
||||
|
||||
def parse_variable(
|
||||
file: str,
|
||||
line_numb: int,
|
||||
get_variable: Callable[[str], SnippetVariable],
|
||||
key: str,
|
||||
value: str,
|
||||
):
|
||||
parts = key.split(".")
|
||||
|
||||
if len(parts) != 2:
|
||||
error(file, line_numb, f"Invalid variable key '{key}'")
|
||||
return
|
||||
|
||||
name = parts[0][1:]
|
||||
field = parts[1]
|
||||
|
||||
match field:
|
||||
case "insertionFormatter":
|
||||
get_variable(name).insertion_formatters = parse_vector_value(value)
|
||||
case "wrapperPhrase":
|
||||
get_variable(name).wrapper_phrases = parse_vector_value(value)
|
||||
case "wrapperScope":
|
||||
get_variable(name).wrapper_scope = value
|
||||
case _:
|
||||
warn(file, line_numb, f"Unknown variable key '{key}'")
|
||||
|
||||
|
||||
def parse_body(text: str) -> Union[str, None]:
|
||||
# Find first line that is not empty. Preserve indentation.
|
||||
match_leading = re.search(r"^[ \t]*\S", text, flags=re.MULTILINE)
|
||||
|
||||
if match_leading is None:
|
||||
return None
|
||||
|
||||
return text[match_leading.start() :].rstrip()
|
||||
|
||||
|
||||
def parse_vector_value(value: str) -> list[str]:
|
||||
return [v.strip() for v in value.split("|")]
|
||||
|
||||
|
||||
def error(file: str, line: int, message: str):
|
||||
logging.error(f"{file}:{line+1} | {message}")
|
||||
|
||||
|
||||
def warn(file: str, line: int, message: str):
|
||||
logging.warning(f"{file}:{line+1} | {message}")
|
||||
Reference in New Issue
Block a user