zedx 0.2.0 → 0.3.1

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.
package/README.md CHANGED
@@ -2,10 +2,15 @@
2
2
 
3
3
  Boilerplate generator for [Zed Editor](https://zed.dev/) extensions.
4
4
 
5
+ ![screenshot](./assets/screenshot1.png)
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
8
10
  npm install -g zedx
11
+
12
+ # or
13
+ brew install tahayvr/tap/zedx
9
14
  ```
10
15
 
11
16
  ### Usage
@@ -23,6 +28,7 @@ zedx version major # 1.2.3 → 2.0.0
23
28
 
24
29
  ### Supported extension types:
25
30
 
26
- 1. Themes
31
+ 1. **Themes** - Color schemes for the editor
32
+ 2. **Languages** - Syntax highlighting, indentation, and optional LSP support
27
33
 
28
- (more coming soon)
34
+ You can choose to include theme, language, or both when creating an extension.
package/dist/generator.js CHANGED
@@ -13,14 +13,31 @@ async function renderTemplate(templatePath, data) {
13
13
  }
14
14
  export async function generateExtension(options, targetDir) {
15
15
  await fs.ensureDir(targetDir);
16
- const extToml = await renderTemplate(path.join(TEMPLATE_DIR, 'base/extension.toml.ejs'), options);
16
+ const extData = {
17
+ ...options,
18
+ grammarRepo: options.grammarRepo || '',
19
+ grammarRev: options.grammarRev || '',
20
+ languageName: options.languageName || 'My Language'
21
+ };
22
+ const extToml = await renderTemplate(path.join(TEMPLATE_DIR, 'base/extension.toml.ejs'), extData);
17
23
  await fs.writeFile(path.join(targetDir, 'extension.toml'), extToml);
24
+ const readmeData = {
25
+ ...extData,
26
+ languageId: options.languageId || 'my-language'
27
+ };
28
+ const readme = await renderTemplate(path.join(TEMPLATE_DIR, 'base/readme.md.ejs'), readmeData);
29
+ await fs.writeFile(path.join(targetDir, 'README.md'), readme);
18
30
  const licensePath = path.join(TEMPLATE_DIR, 'base/licenses', options.license);
19
31
  let licenseContent = await fs.readFile(licensePath, 'utf-8');
20
32
  licenseContent = licenseContent.replaceAll('{{YEAR}}', new Date().getFullYear().toString());
21
33
  licenseContent = licenseContent.replaceAll('{{AUTHOR}}', options.author);
22
34
  await fs.writeFile(path.join(targetDir, 'LICENSE'), licenseContent);
23
- await generateTheme(options, targetDir);
35
+ if (options.types.includes('theme')) {
36
+ await generateTheme(options, targetDir);
37
+ }
38
+ if (options.types.includes('language')) {
39
+ await generateLanguage(options, targetDir);
40
+ }
24
41
  }
25
42
  async function generateTheme(options, targetDir) {
26
43
  const themeDir = path.join(targetDir, 'themes');
@@ -35,3 +52,33 @@ async function generateTheme(options, targetDir) {
35
52
  const themeJson = await renderTemplate(path.join(TEMPLATE_DIR, 'theme/theme.json.ejs'), themeData);
36
53
  await fs.writeFile(path.join(themeDir, `${options.id}.json`), themeJson);
37
54
  }
55
+ async function generateLanguage(options, targetDir) {
56
+ const languageDir = path.join(targetDir, 'languages', options.languageId);
57
+ await fs.ensureDir(languageDir);
58
+ const data = {
59
+ ...options,
60
+ pathSuffixes: options.pathSuffixes || [],
61
+ lineComments: options.lineComments || ['//', '#']
62
+ };
63
+ const configToml = await renderTemplate(path.join(TEMPLATE_DIR, 'language/config.toml.ejs'), data);
64
+ await fs.writeFile(path.join(languageDir, 'config.toml'), configToml);
65
+ const queryFiles = [
66
+ 'highlights.scm',
67
+ 'brackets.scm',
68
+ 'outline.scm',
69
+ 'indents.scm',
70
+ 'injections.scm',
71
+ 'overrides.scm',
72
+ 'textobjects.scm',
73
+ 'redactions.scm',
74
+ 'runnables.scm'
75
+ ];
76
+ for (const file of queryFiles) {
77
+ const templatePath = path.join(TEMPLATE_DIR, 'language', file);
78
+ if (await fs.pathExists(templatePath)) {
79
+ let content = await fs.readFile(templatePath, 'utf-8');
80
+ content = ejs.render(content, data);
81
+ await fs.writeFile(path.join(languageDir, file), content);
82
+ }
83
+ }
84
+ }
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as p from '@clack/prompts';
4
4
  import color from 'picocolors';
5
5
  import { Command } from 'commander';
6
6
  import fs from 'fs-extra';
7
- import { promptUser, promptThemeDetails } from './prompts.js';
7
+ import { promptUser, promptThemeDetails, promptLanguageDetails } from './prompts.js';
8
8
  import { generateExtension } from './generator.js';
9
9
  function bumpVersion(version, type) {
10
10
  const [major, minor, patch] = version.split('.').map(Number);
@@ -54,10 +54,15 @@ async function main() {
54
54
  await bumpExtensionVersion(type);
55
55
  });
56
56
  if (process.argv.length <= 2) {
57
- // No command provided, run interactive mode
58
57
  const options = await promptUser();
59
- const themeDetails = await promptThemeDetails();
60
- Object.assign(options, themeDetails);
58
+ if (options.types.includes('theme')) {
59
+ const themeDetails = await promptThemeDetails();
60
+ Object.assign(options, themeDetails);
61
+ }
62
+ if (options.types.includes('language')) {
63
+ const languageDetails = await promptLanguageDetails();
64
+ Object.assign(options, languageDetails);
65
+ }
61
66
  const targetDir = path.join(getCallerDir(), options.id);
62
67
  await generateExtension(options, targetDir);
63
68
  p.outro(`${color.green('✓')} ${color.bold('Extension created successfully!')}\n` +
package/dist/prompts.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type { ExtensionOptions } from './types/index.js';
1
+ import type { ExtensionOptions, LanguageOptions } from './types/index.js';
2
2
  export declare function promptUser(): Promise<ExtensionOptions>;
3
3
  export declare function promptThemeDetails(): Promise<{
4
4
  themeName: string;
5
5
  appearance: 'light' | 'dark' | 'both';
6
6
  }>;
7
+ export declare function promptLanguageDetails(): Promise<Partial<LanguageOptions>>;
package/dist/prompts.js CHANGED
@@ -28,7 +28,7 @@ export async function promptUser() {
28
28
  process.exit(0);
29
29
  }
30
30
  const idValue = id || idDefault;
31
- const descriptionDefault = 'A Zed theme';
31
+ const descriptionDefault = 'A Zed extension';
32
32
  const description = await p.text({
33
33
  message: 'Description:',
34
34
  placeholder: descriptionDefault
@@ -50,7 +50,7 @@ export async function promptUser() {
50
50
  p.cancel('Cancelled.');
51
51
  process.exit(0);
52
52
  }
53
- const repositoryDefault = `https://github.com/username/zed-theme.git`;
53
+ const repositoryDefault = `https://github.com/username/${idValue}.git`;
54
54
  const repository = await p.text({
55
55
  message: 'GitHub repository URL:',
56
56
  initialValue: repositoryDefault
@@ -77,6 +77,18 @@ export async function promptUser() {
77
77
  p.cancel('Cancelled.');
78
78
  process.exit(0);
79
79
  }
80
+ const extensionTypes = await p.multiselect({
81
+ message: 'What do you want to include in your extension?',
82
+ options: [
83
+ { value: 'theme', label: 'Theme', hint: 'Color scheme for the editor' },
84
+ { value: 'language', label: 'Language', hint: 'Syntax highlighting, indentation, etc.' }
85
+ ],
86
+ required: true
87
+ });
88
+ if (p.isCancel(extensionTypes)) {
89
+ p.cancel('Cancelled.');
90
+ process.exit(0);
91
+ }
80
92
  const options = {
81
93
  name: nameValue,
82
94
  id: idValue,
@@ -84,7 +96,7 @@ export async function promptUser() {
84
96
  author: String(author),
85
97
  repository: repositoryValue,
86
98
  license: license,
87
- types: ['theme']
99
+ types: extensionTypes
88
100
  };
89
101
  return options;
90
102
  }
@@ -115,3 +127,18 @@ export async function promptThemeDetails() {
115
127
  appearance: appearance
116
128
  };
117
129
  }
130
+ export async function promptLanguageDetails() {
131
+ const languageName = await p.text({
132
+ message: 'Language name:',
133
+ placeholder: 'My Language'
134
+ });
135
+ if (p.isCancel(languageName)) {
136
+ p.cancel('Cancelled.');
137
+ process.exit(0);
138
+ }
139
+ const result = {
140
+ languageName: String(languageName),
141
+ languageId: String(languageName).toLowerCase().replace(/\s+/g, '-')
142
+ };
143
+ return result;
144
+ }
@@ -2,6 +2,22 @@ id = "<%= id %>"
2
2
  name = "<%= name %>"
3
3
  version = "0.0.1"
4
4
  schema_version = 1
5
- authors = ["<%= author %>"]
5
+ authors = ["<%- author %>"]
6
6
  description = "<%= description %>"
7
7
  repository = "<%= repository %>"
8
+
9
+ <% if (types.includes('language') && grammarRepo) { %>
10
+ [grammars.<%= languageId %>]
11
+ repository = "<%= grammarRepo %>"
12
+ rev = "<%= grammarRev || 'main' %>"
13
+ <% } else if (types.includes('language')) { %>
14
+ # [grammars.<%= languageId %>]
15
+ # repository = "https://github.com/user/tree-sitter-<%= languageId %>"
16
+ # rev = "main"
17
+ <% } %>
18
+
19
+ <% if (types.includes('language')) { %>
20
+ # [language_servers.my-lsp]
21
+ # name = "My Language LSP"
22
+ # languages = ["<%= languageName %>"]
23
+ <% } %>
@@ -0,0 +1,34 @@
1
+ <%= name %>
2
+ <%= "=".repeat(name.length) %>
3
+
4
+ <%= description %>
5
+
6
+ ## Installation
7
+
8
+ 1. Open Zed
9
+ 2. Run `Extensions > Install Dev Extension`
10
+ 3. Select the folder for this extension
11
+
12
+ ## Development
13
+
14
+ ### Themes
15
+
16
+ Edit `themes/<%= id %>.json` to customize colors. See [Zed Theme Documentation](https://zed.dev/docs/themes) for available tokens.
17
+
18
+ ### Languages
19
+
20
+ Edit `languages/<%= languageId %>/config.toml`.
21
+
22
+ #### Tree-sitter Grammar
23
+
24
+ To add syntax highlighting, you'll need a Tree-sitter grammar:
25
+
26
+ 1. Find or create a grammar repo. Try [tree-sitter](https://github.com/tree-sitter/tree-sitter)
27
+ 2. Uncomment and fill in the `[grammars.<%= languageId %>]` section in `extension.toml`
28
+ 3. Edit the `.scm` files in `languages/<%= languageId %>/`
29
+
30
+ See [Zed Documentation](https://zed.dev/docs/extensions/languages) for details.
31
+
32
+ ## Publishing
33
+
34
+ Run `zedx version patch|minor|major` to bump the version, then create a GitHub release.
@@ -0,0 +1,23 @@
1
+ ; =============================================================================
2
+ ; Bracket Matching Queries
3
+ ; =============================================================================
4
+ ; This file defines matching brackets for rainbow bracket highlighting.
5
+ ; See: https://zed.dev/docs/extensions/languages#bracket-matching
6
+ ;
7
+ ; Captures:
8
+ ; @open - Opening bracket
9
+ ; @close - Closing bracket
10
+ ;
11
+ ; To exclude from rainbow brackets, add: (#set! rainbow.exclude)
12
+ ;
13
+ ; Example:
14
+ ; ("(" @open ")" @close)
15
+ ; ("[" @open "]" @close)
16
+ ; ("{" @open "}" @close)
17
+ ;
18
+ ; Note: Quotes need escaping in .scm files:
19
+ ; ("\"" @open "\"" @close)
20
+
21
+ ("(" @open ")" @close)
22
+ ("[" @open "]" @close)
23
+ ("{" @open "}" @close)
@@ -0,0 +1,26 @@
1
+ # name (required): The human readable name shown in the Select Language dropdown
2
+ name = "<%= languageName %>"
3
+
4
+ # grammar (required): The name of a Tree-sitter grammar (must match grammar registration in extension.toml)
5
+ grammar = "<%= languageId %>"
6
+
7
+ # path_suffixes: Array of file suffixes associated with this language (e.g., ["myl", "my"])
8
+ # Unlike file_types in settings, this does not support glob patterns
9
+ # path_suffixes = []
10
+
11
+ # line_comments: Array of strings used to identify line comments
12
+ # Used for editor::ToggleComments keybind (cmd-/ or ctrl-/)
13
+ # line_comments = ["// ", "# "]
14
+
15
+ # tab_size: The indentation/tab size used for this language (default is 4)
16
+ # tab_size = 4
17
+
18
+ # hard_tabs: Whether to indent with tabs (true) or spaces (false, the default)
19
+ # hard_tabs = false
20
+
21
+ # first_line_pattern: A regular expression to match files based on their first line
22
+ # Useful for identifying files by shebang (e.g., "^#!.*\\bbash\\b" for shell scripts)
23
+ # first_line_pattern = ""
24
+
25
+ # debuggers: Array of debugger identifiers for ordering in the New Process Modal
26
+ # debuggers = []
@@ -0,0 +1,32 @@
1
+ ; =============================================================================
2
+ ; Syntax Highlighting Queries
3
+ ; =============================================================================
4
+ ; This file defines syntax highlighting rules using Tree-sitter queries.
5
+ ; See: https://zed.dev/docs/extensions/languages#syntax-highlighting
6
+ ;
7
+ ; Capture names (prefix with @):
8
+ ; @string - String literals
9
+ ; @number - Numeric values
10
+ ; @comment - Comments
11
+ ; @keyword - Keywords
12
+ ; @function - Functions
13
+ ; @type - Types
14
+ ; @variable - Variables
15
+ ; @property - Properties
16
+ ; @operator - Operators
17
+ ; @punctuation - Punctuation
18
+ ; @constant - Constants
19
+ ; @attribute - Attributes
20
+ ; @tag - Tags
21
+ ;
22
+ ; Example:
23
+ ; (string) @string
24
+ ; (number) @number
25
+ ; (comment) @comment
26
+ ;
27
+ ; Learn more about Tree-sitter queries:
28
+ ; https://tree-sitter.github.io/tree-sitter/using-parsers/queries
29
+
30
+ (string) @string
31
+ (number) @number
32
+ (comment) @comment
@@ -0,0 +1,17 @@
1
+ ; =============================================================================
2
+ ; Auto-Indentation Queries
3
+ ; =============================================================================
4
+ ; This file defines indentation rules for automatic formatting.
5
+ ; See: https://zed.dev/docs/extensions/languages#auto-indentation
6
+ ;
7
+ ; Captures:
8
+ ; @end - Closing bracket/brace that ends an indented block
9
+ ; @indent - Entire block that should increase indentation
10
+ ;
11
+ ; Example for block-based languages:
12
+ ; (block "}" @end) @indent
13
+ ; (function "}" @end) @indent
14
+ ;
15
+ ; Example for indentation-based languages:
16
+ ; (list_item) @indent
17
+
@@ -0,0 +1,24 @@
1
+ ; =============================================================================
2
+ ; Code Injection Queries
3
+ ; =============================================================================
4
+ ; This file defines rules for embedding one language within another.
5
+ ; See: https://zed.dev/docs/extensions/languages#code-injections
6
+ ;
7
+ ; Common use cases:
8
+ ; - SQL queries in Python strings
9
+ ; - Code blocks in Markdown
10
+ ; - CSS in HTML style tags
11
+ ; - JavaScript in JSX/TSX
12
+ ;
13
+ ; Captures:
14
+ ; @injection.language - The language identifier (e.g., "python", "javascript")
15
+ ; @injection.content - The content to treat as a different language
16
+ ;
17
+ ; Example for Markdown code blocks:
18
+ ; (fenced_code_block
19
+ ; (info_string (language) @injection.language)
20
+ ; (code_fence_content) @injection.content)
21
+ ;
22
+ ; Example for inline markdown:
23
+ ; ((inline) @content (#set! injection.language "markdown-inline"))
24
+
@@ -0,0 +1,17 @@
1
+ ; =============================================================================
2
+ ; Code Outline Queries
3
+ ; =============================================================================
4
+ ; This file defines the structure shown in the code outline panel.
5
+ ; See: https://zed.dev/docs/extensions/languages#code-outlinestructure
6
+ ;
7
+ ; Captures:
8
+ ; @name - Display name for the outline item
9
+ ; @item - The entire element to show in outline
10
+ ; @context - Provides context for the item
11
+ ; @context.extra - Additional contextual info
12
+ ; @annotation - Annotations (doc comments, decorators)
13
+ ;
14
+ ; Example:
15
+ ; (function_definition name: (identifier) @name) @item
16
+ ; (class_declaration name: (type_identifier) @name) @item
17
+
@@ -0,0 +1,20 @@
1
+ ; =============================================================================
2
+ ; Syntax Override Queries
3
+ ; =============================================================================
4
+ ; This file defines scoped overrides for editor settings.
5
+ ; See: https://zed.dev/docs/extensions/languages#syntax-overrides
6
+ ;
7
+ ; Available overrides:
8
+ ; word_characters - Characters considered part of a word
9
+ ; completion_query_characters - Characters that trigger autocomplete
10
+ ;
11
+ ; Use .inclusive suffix to make range inclusive (default is exclusive):
12
+ ; (comment) @comment.inclusive
13
+ ;
14
+ ; Example - JavaScript strings with hyphen completion:
15
+ ; (string) @string
16
+ ; ; Then set in config.toml:
17
+ ; ; [overrides.string]
18
+ ; ; completion_query_characters = ["-"]
19
+
20
+ (string) @string
@@ -0,0 +1,16 @@
1
+ ; =============================================================================
2
+ ; Text Redaction Queries
3
+ ; =============================================================================
4
+ ; This file defines content to redact when sharing screen/collaborating.
5
+ ; See: https://zed.dev/docs/extensions/languages#text-redactions
6
+ ;
7
+ ; Redacted content is rendered in a neutral style to protect sensitive data.
8
+ ;
9
+ ; Captures:
10
+ ; @redact - Content to be redacted
11
+ ;
12
+ ; Example:
13
+ ; (string) @redact
14
+ ; (number) @redact
15
+ ; (environment_variable (string) @redact)
16
+
@@ -0,0 +1,25 @@
1
+ ; =============================================================================
2
+ ; Runnable Code Detection Queries
3
+ ; =============================================================================
4
+ ; This file defines rules for detecting runnable code blocks.
5
+ ; See: https://zed.dev/docs/extensions/languages#runnable-code-detection
6
+ ;
7
+ ; Adds run buttons to the editor gutter for executable code/scripts.
8
+ ;
9
+ ; Captures:
10
+ ; @run - Where to place the run button
11
+ ; @script - Also captures the script name
12
+ ;
13
+ ; Other captures (except underscore-prefixed) are exposed as:
14
+ ; ZED_CUSTOM_<CAPTURE_NAME> environment variables
15
+ ;
16
+ ; Tags (using #set! tag):
17
+ ; (#set! tag <tag-name>) - Additional metadata for the runnable
18
+ ;
19
+ ; Example for package.json scripts:
20
+ ; (pair
21
+ ; key: (string (string_content) @_name (#eq? @_name "scripts"))
22
+ ; value: (object
23
+ ; (pair
24
+ ; key: (string (string_content) @run @script))))
25
+
@@ -0,0 +1,26 @@
1
+ ; =============================================================================
2
+ ; Text Object Queries
3
+ ; =============================================================================
4
+ ; This file defines text objects for Vim mode navigation.
5
+ ; See: https://zed.dev/docs/extensions/languages#text-objects
6
+ ;
7
+ ; Vim motions using these:
8
+ ; [m / ]m - Previous/next function (or @function.around)
9
+ ; [M / ]M - Previous/next class (or @class.around)
10
+ ; af / if - Around/inside function
11
+ ; ac / ic - Around/inside class
12
+ ; gc - Around comment
13
+ ;
14
+ ; Captures:
15
+ ; @function.around - Entire function definition
16
+ ; @function.inside - Function body (inside braces)
17
+ ; @class.around - Entire class definition
18
+ ; @class.inside - Class contents
19
+ ; @comment.around - Entire comment block
20
+ ; @comment.inside - Comment contents
21
+ ;
22
+ ; Example:
23
+ ; (function_definition) @function.around
24
+ ; (function_definition body: (_) @function.inside)
25
+ ; (class_declaration) @class.around
26
+
@@ -1,4 +1,4 @@
1
- export type ExtensionType = 'theme';
1
+ export type ExtensionType = 'theme' | 'language';
2
2
  export type License = 'Apache-2.0' | 'BSD-2-Clause' | 'BSD-3-Clause' | 'GPL-3.0' | 'LGPL-3.0' | 'MIT' | 'Zlib';
3
3
  export interface ExtensionOptions {
4
4
  name: string;
@@ -14,3 +14,15 @@ export interface ThemeOptions extends ExtensionOptions {
14
14
  themeName: string;
15
15
  appearance: 'light' | 'dark' | 'both';
16
16
  }
17
+ export interface LanguageOptions extends ExtensionOptions {
18
+ languageName: string;
19
+ languageId: string;
20
+ pathSuffixes?: string[];
21
+ lineComments?: string[];
22
+ grammarRepo?: string;
23
+ grammarRev?: string;
24
+ hasLsp?: boolean;
25
+ lspServerName?: string;
26
+ lspCommand?: string;
27
+ lspArgs?: string[];
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zedx",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Boilerplate generator for Zed Edittor extensions.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",