zedx 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,16 @@
1
1
  # zedx
2
2
 
3
- Boilerplate generator for Zed extensions.
3
+ Boilerplate generator for [Zed Editor](https://zed.dev/) extensions.
4
+
5
+ ![screenshot](./assets/screenshot1.png)
4
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
@@ -16,13 +21,14 @@ zedx
16
21
 
17
22
  # Bump extension version
18
23
  # Run inside extension dir
19
- zedx bump patch # 1.2.3 → 1.2.4
20
- zedx bump minor # 1.2.3 → 1.3.0
21
- zedx bump major # 1.2.3 → 2.0.0
24
+ zedx version patch # 1.2.3 → 1.2.4
25
+ zedx version minor # 1.2.3 → 1.3.0
26
+ zedx version major # 1.2.3 → 2.0.0
22
27
  ```
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.
@@ -1,2 +1,2 @@
1
- import type { ExtensionOptions } from "./types/index.js";
1
+ import type { ExtensionOptions } from './types/index.js';
2
2
  export declare function generateExtension(options: ExtensionOptions, targetDir: string): Promise<void>;
package/dist/generator.js CHANGED
@@ -1,37 +1,67 @@
1
- import fs from "fs-extra";
2
- import path from "path";
3
- import { fileURLToPath } from "url";
4
- import ejs from "ejs";
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import ejs from 'ejs';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
- const isDev = __dirname.includes("/src/");
8
- const PROJECT_ROOT = isDev ? path.join(__dirname, "..") : __dirname;
9
- const TEMPLATE_DIR = path.join(PROJECT_ROOT, "templates");
7
+ const isDev = __dirname.includes('/src/');
8
+ const PROJECT_ROOT = isDev ? path.join(__dirname, '..') : __dirname;
9
+ const TEMPLATE_DIR = path.join(PROJECT_ROOT, 'templates');
10
10
  async function renderTemplate(templatePath, data) {
11
- const template = await fs.readFile(templatePath, "utf-8");
11
+ const template = await fs.readFile(templatePath, 'utf-8');
12
12
  return ejs.render(template, 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);
17
- await fs.writeFile(path.join(targetDir, "extension.toml"), extToml);
18
- const licensePath = path.join(TEMPLATE_DIR, "base/licenses", options.license);
19
- let licenseContent = await fs.readFile(licensePath, "utf-8");
20
- licenseContent = licenseContent.replaceAll("{{YEAR}}", new Date().getFullYear().toString());
21
- licenseContent = licenseContent.replaceAll("{{AUTHOR}}", options.author);
22
- await fs.writeFile(path.join(targetDir, "LICENSE"), licenseContent);
23
- await generateTheme(options, targetDir);
16
+ const extToml = await renderTemplate(path.join(TEMPLATE_DIR, 'base/extension.toml.ejs'), options);
17
+ await fs.writeFile(path.join(targetDir, 'extension.toml'), extToml);
18
+ const licensePath = path.join(TEMPLATE_DIR, 'base/licenses', options.license);
19
+ let licenseContent = await fs.readFile(licensePath, 'utf-8');
20
+ licenseContent = licenseContent.replaceAll('{{YEAR}}', new Date().getFullYear().toString());
21
+ licenseContent = licenseContent.replaceAll('{{AUTHOR}}', options.author);
22
+ await fs.writeFile(path.join(targetDir, 'LICENSE'), licenseContent);
23
+ if (options.types.includes('theme')) {
24
+ await generateTheme(options, targetDir);
25
+ }
26
+ if (options.types.includes('language')) {
27
+ await generateLanguage(options, targetDir);
28
+ }
24
29
  }
25
30
  async function generateTheme(options, targetDir) {
26
- const themeDir = path.join(targetDir, "themes");
31
+ const themeDir = path.join(targetDir, 'themes');
27
32
  await fs.ensureDir(themeDir);
28
- const appearance = options.appearance || "dark";
29
- const appearances = appearance === "both" ? ["dark", "light"] : [appearance];
33
+ const appearance = options.appearance || 'dark';
34
+ const appearances = appearance === 'both' ? ['dark', 'light'] : [appearance];
30
35
  const themeData = {
31
36
  ...options,
32
- themeName: options.themeName || "My Theme",
33
- appearances,
37
+ themeName: options.themeName || 'My Theme',
38
+ appearances
34
39
  };
35
- const themeJson = await renderTemplate(path.join(TEMPLATE_DIR, "theme/theme.json.ejs"), themeData);
40
+ const themeJson = await renderTemplate(path.join(TEMPLATE_DIR, 'theme/theme.json.ejs'), themeData);
36
41
  await fs.writeFile(path.join(themeDir, `${options.id}.json`), themeJson);
37
42
  }
43
+ async function generateLanguage(options, targetDir) {
44
+ const languageDir = path.join(targetDir, 'languages', options.languageId);
45
+ await fs.ensureDir(languageDir);
46
+ const configToml = await renderTemplate(path.join(TEMPLATE_DIR, 'language/config.toml.ejs'), options);
47
+ await fs.writeFile(path.join(languageDir, 'config.toml'), configToml);
48
+ const queryFiles = [
49
+ 'highlights.scm',
50
+ 'brackets.scm',
51
+ 'outline.scm',
52
+ 'indents.scm',
53
+ 'injections.scm',
54
+ 'overrides.scm',
55
+ 'textobjects.scm',
56
+ 'redactions.scm',
57
+ 'runnables.scm'
58
+ ];
59
+ for (const file of queryFiles) {
60
+ const templatePath = path.join(TEMPLATE_DIR, 'language', file);
61
+ if (await fs.pathExists(templatePath)) {
62
+ let content = await fs.readFile(templatePath, 'utf-8');
63
+ content = ejs.render(content, options);
64
+ await fs.writeFile(path.join(languageDir, file), content);
65
+ }
66
+ }
67
+ }
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env node
2
- import path from "path";
3
- import * as p from "@clack/prompts";
4
- import color from "picocolors";
5
- import { Command } from "commander";
6
- import fs from "fs-extra";
7
- import { promptUser, promptThemeDetails } from "./prompts.js";
8
- import { generateExtension } from "./generator.js";
2
+ import path from 'path';
3
+ import * as p from '@clack/prompts';
4
+ import color from 'picocolors';
5
+ import { Command } from 'commander';
6
+ import fs from 'fs-extra';
7
+ import { promptUser, promptThemeDetails, promptLanguageDetails } from './prompts.js';
8
+ import { generateExtension } from './generator.js';
9
9
  function bumpVersion(version, type) {
10
- const [major, minor, patch] = version.split(".").map(Number);
10
+ const [major, minor, patch] = version.split('.').map(Number);
11
11
  switch (type) {
12
- case "major":
12
+ case 'major':
13
13
  return `${major + 1}.0.0`;
14
- case "minor":
14
+ case 'minor':
15
15
  return `${major}.${minor + 1}.0`;
16
- case "patch":
16
+ case 'patch':
17
17
  return `${major}.${minor}.${patch + 1}`;
18
18
  }
19
19
  }
@@ -22,15 +22,15 @@ function getCallerDir() {
22
22
  }
23
23
  async function bumpExtensionVersion(type) {
24
24
  const callerDir = getCallerDir();
25
- const tomlPath = path.join(callerDir, "extension.toml");
25
+ const tomlPath = path.join(callerDir, 'extension.toml');
26
26
  if (!(await fs.pathExists(tomlPath))) {
27
- p.log.error(color.red("No extension.toml found in current directory."));
27
+ p.log.error(color.red('No extension.toml found in current directory.'));
28
28
  process.exit(1);
29
29
  }
30
- const content = await fs.readFile(tomlPath, "utf-8");
30
+ const content = await fs.readFile(tomlPath, 'utf-8');
31
31
  const versionMatch = content.match(/version\s*=\s*"(\d+\.\d+\.\d+)"/);
32
32
  if (!versionMatch) {
33
- p.log.error(color.red("Could not find version in extension.toml"));
33
+ p.log.error(color.red('Could not find version in extension.toml'));
34
34
  process.exit(1);
35
35
  }
36
36
  const currentVersion = versionMatch[1];
@@ -41,30 +41,38 @@ async function bumpExtensionVersion(type) {
41
41
  }
42
42
  async function main() {
43
43
  const program = new Command();
44
- program.name("zedx").description("Boilerplate generator for Zed extensions");
44
+ program.name('zedx').description('Boilerplate generator for Zed Editor extensions.');
45
45
  program
46
- .command("bump")
47
- .description("Bump the version of the extension")
48
- .argument("<type>", "Version bump type: major, minor, or patch")
46
+ .command('version')
47
+ .description('Bump the version of the extension')
48
+ .argument('<type>', 'Version bump type: major, minor, or patch')
49
49
  .action(async (type) => {
50
- if (!["major", "minor", "patch"].includes(type)) {
51
- p.log.error(color.red("Invalid bump type. Use: major, minor, or patch"));
50
+ if (!['major', 'minor', 'patch'].includes(type)) {
51
+ p.log.error(color.red('Invalid bump type. Use: major, minor, or patch'));
52
52
  process.exit(1);
53
53
  }
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
- // Final success message
64
- p.outro(`${color.green("✓")} ${color.bold("Extension created successfully!")}\n\n` +
65
- `Location: ${color.yellow(targetDir)}\n`);
66
- p.note(`Open Zed and install theme as dev extension: Extensions > Install Dev Extension`, "Next steps");
67
- p.outro(`More info: ${color.underline(color.yellow("https://zed.dev/docs/extensions/developing-extensions"))}`);
68
+ p.outro(`${color.green('✓')} ${color.bold('Extension created successfully!')}\n` +
69
+ `${color.gray('─'.repeat(40))}\n` +
70
+ `${color.dim('Location:')} ${color.cyan(targetDir)}`);
71
+ p.outro(`${color.yellow('⚡')} ${color.bold('Next steps')}\n\n` +
72
+ ` ${color.gray('1.')} Open Zed\n` +
73
+ ` ${color.gray('2.')} ${color.white('Extensions > Install Dev Extension')}\n` +
74
+ ` ${color.gray('3.')} Select ${color.cyan(options.id)} folder\n\n` +
75
+ `${color.dim('Learn more:')} ${color.underline(color.blue('https://zed.dev/docs/extensions/developing-extensions'))}`);
68
76
  return;
69
77
  }
70
78
  program.parse(process.argv);
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
- appearance: "light" | "dark" | "both";
5
+ appearance: 'light' | 'dark' | 'both';
6
6
  }>;
7
+ export declare function promptLanguageDetails(): Promise<Partial<LanguageOptions>>;
package/dist/prompts.js CHANGED
@@ -1,79 +1,92 @@
1
- import * as p from "@clack/prompts";
2
- import color from "picocolors";
1
+ import * as p from '@clack/prompts';
2
+ import color from 'picocolors';
3
3
  export async function promptUser() {
4
- p.intro(color.bgBlue(" zedx "));
5
- const nameDefault = "my-zed-extension";
4
+ p.intro(`${color.bgBlue(color.bold(' zedx '))} ${color.blue('Boilerplate generator for Zed Editor extensions.')}`);
5
+ const nameDefault = 'my-zed-extension';
6
6
  const name = await p.text({
7
- message: "Project name:",
8
- placeholder: nameDefault,
7
+ message: 'Project name:',
8
+ placeholder: nameDefault
9
9
  });
10
10
  if (p.isCancel(name)) {
11
- p.cancel("Cancelled.");
11
+ p.cancel('Cancelled.');
12
12
  process.exit(0);
13
13
  }
14
14
  const nameValue = name || nameDefault;
15
- const idDefault = nameValue.toLowerCase().replace(/\s+/g, "-");
15
+ const idDefault = nameValue.toLowerCase().replace(/\s+/g, '-');
16
16
  const id = await p.text({
17
- message: "Extension ID:",
17
+ message: 'Extension ID:',
18
18
  placeholder: idDefault,
19
19
  validate: (value) => {
20
- if (value && value.includes(" "))
21
- return "ID cannot contain spaces";
20
+ if (value && value.includes(' '))
21
+ return 'ID cannot contain spaces';
22
22
  if (value && value !== value.toLowerCase())
23
- return "ID must be lowercase";
24
- },
23
+ return 'ID must be lowercase';
24
+ }
25
25
  });
26
26
  if (p.isCancel(id)) {
27
- p.cancel("Cancelled.");
27
+ p.cancel('Cancelled.');
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
- message: "Description:",
34
- placeholder: descriptionDefault,
33
+ message: 'Description:',
34
+ placeholder: descriptionDefault
35
35
  });
36
36
  if (p.isCancel(description)) {
37
- p.cancel("Cancelled.");
37
+ p.cancel('Cancelled.');
38
38
  process.exit(0);
39
39
  }
40
40
  const descriptionValue = description || descriptionDefault;
41
41
  const author = await p.text({
42
- message: "Author name:",
42
+ message: 'Author name:',
43
+ placeholder: 'name <username@example.com>',
43
44
  validate: (value) => {
44
45
  if (!value || value.length === 0)
45
- return "Author is required";
46
- },
46
+ return 'Author is required';
47
+ }
47
48
  });
48
49
  if (p.isCancel(author)) {
49
- p.cancel("Cancelled.");
50
+ p.cancel('Cancelled.');
50
51
  process.exit(0);
51
52
  }
52
- const repositoryDefault = `https://github.com/${author ?? ""}/zed-theme.git`;
53
+ const repositoryDefault = `https://github.com/username/${idValue}.git`;
53
54
  const repository = await p.text({
54
- message: "GitHub repository URL:",
55
- initialValue: repositoryDefault,
55
+ message: 'GitHub repository URL:',
56
+ initialValue: repositoryDefault
56
57
  });
57
58
  if (p.isCancel(repository)) {
58
- p.cancel("Cancelled.");
59
+ p.cancel('Cancelled.');
59
60
  process.exit(0);
60
61
  }
61
62
  const repositoryValue = repository || repositoryDefault;
62
63
  const license = await p.select({
63
- message: "License:",
64
+ message: 'License:',
64
65
  options: [
65
- { value: "Apache-2.0", label: "Apache 2.0" },
66
- { value: "BSD-2-Clause", label: "BSD 2-Clause" },
67
- { value: "BSD-3-Clause", label: "BSD 3-Clause" },
68
- { value: "GPL-3.0", label: "GNU GPLv3" },
69
- { value: "LGPL-3.0", label: "GNU LGPLv3" },
70
- { value: "MIT", label: "MIT" },
71
- { value: "Zlib", label: "zlib" },
66
+ { value: 'Apache-2.0', label: 'Apache 2.0' },
67
+ { value: 'BSD-2-Clause', label: 'BSD 2-Clause' },
68
+ { value: 'BSD-3-Clause', label: 'BSD 3-Clause' },
69
+ { value: 'GPL-3.0', label: 'GNU GPLv3' },
70
+ { value: 'LGPL-3.0', label: 'GNU LGPLv3' },
71
+ { value: 'MIT', label: 'MIT' },
72
+ { value: 'Zlib', label: 'zlib' }
72
73
  ],
73
- initialValue: "MIT",
74
+ initialValue: 'MIT'
74
75
  });
75
76
  if (p.isCancel(license)) {
76
- p.cancel("Cancelled.");
77
+ p.cancel('Cancelled.');
78
+ process.exit(0);
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.');
77
90
  process.exit(0);
78
91
  }
79
92
  const options = {
@@ -83,34 +96,54 @@ export async function promptUser() {
83
96
  author: String(author),
84
97
  repository: repositoryValue,
85
98
  license: license,
86
- types: ["theme"],
99
+ types: extensionTypes
87
100
  };
88
101
  return options;
89
102
  }
90
103
  export async function promptThemeDetails() {
91
104
  const themeName = await p.text({
92
- message: "Theme name:",
93
- placeholder: "My Theme",
105
+ message: 'Theme name:',
106
+ placeholder: 'My Theme'
94
107
  });
95
108
  if (p.isCancel(themeName)) {
96
- p.cancel("Cancelled.");
109
+ p.cancel('Cancelled.');
97
110
  process.exit(0);
98
111
  }
99
112
  const appearance = await p.select({
100
- message: "Appearance:",
113
+ message: 'Appearance:',
101
114
  options: [
102
- { value: "dark", label: "Dark" },
103
- { value: "light", label: "Light" },
104
- { value: "both", label: "Both (Dark & Light)" },
115
+ { value: 'dark', label: 'Dark' },
116
+ { value: 'light', label: 'Light' },
117
+ { value: 'both', label: 'Both (Dark & Light)' }
105
118
  ],
106
- initialValue: "dark",
119
+ initialValue: 'dark'
107
120
  });
108
121
  if (p.isCancel(appearance)) {
109
- p.cancel("Cancelled.");
122
+ p.cancel('Cancelled.');
110
123
  process.exit(0);
111
124
  }
112
125
  return {
113
126
  themeName: String(themeName),
114
- appearance: appearance,
127
+ appearance: appearance
128
+ };
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
+ pathSuffixes: [],
143
+ lineComments: [],
144
+ grammarRepo: '',
145
+ grammarRev: '',
146
+ hasLsp: false
115
147
  };
148
+ return result;
116
149
  }
@@ -2,6 +2,19 @@ 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 %>"
13
+ <% } %>
14
+ <% if (hasLsp && lspServerName) { %>
15
+ [language_servers.<%= lspServerName %>]
16
+ name = "<%= lspServerName %>"
17
+ languages = ["<%= languageName %>"]
18
+
19
+ [languages."<%= languageName %>"]
20
+ <% } %>
@@ -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,29 @@
1
+ <%= languageName %>
2
+ <%= "=".repeat(languageName.length) %>
3
+
4
+ ; name (required): The human readable name shown in the Select Language dropdown
5
+ name = "<%= languageName %>"
6
+
7
+ ; grammar (required): The name of a Tree-sitter grammar (must match grammar registration in extension.toml)
8
+ grammar = "<%= languageId %>"
9
+
10
+ ; path_suffixes: Array of file suffixes associated with this language (e.g., ["myl", "my"])
11
+ ; Unlike file_types in settings, this does not support glob patterns
12
+ path_suffixes = <%- pathSuffixes.length > 0 ? JSON.stringify(pathSuffixes) : '[""]' %>
13
+
14
+ ; line_comments: Array of strings used to identify line comments
15
+ ; Used for editor::ToggleComments keybind (cmd-/ or ctrl-/)
16
+ line_comments = <%- lineComments.length > 0 ? JSON.stringify(lineComments) : '[""]' %>
17
+
18
+ ; tab_size: The indentation/tab size used for this language (default is 4)
19
+ ; tab_size = 4
20
+
21
+ ; hard_tabs: Whether to indent with tabs (true) or spaces (false, the default)
22
+ ; hard_tabs = false
23
+
24
+ ; first_line_pattern: A regular expression to match files based on their first line
25
+ ; Useful for identifying files by shebang (e.g., "^#!.*\\bbash\\b" for shell scripts)
26
+ ; first_line_pattern = ""
27
+
28
+ ; debuggers: Array of debugger identifiers for ordering in the New Process Modal
29
+ ; 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,53 +1,53 @@
1
1
  {
2
- "name": "zedx",
3
- "version": "0.1.1",
4
- "description": "Boilerplate generator for Zed extensions",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "bin": {
8
- "zedx": "dist/index.js"
9
- },
10
- "files": [
11
- "dist"
12
- ],
13
- "scripts": {
14
- "build": "tsc && cp -r src/templates dist/",
15
- "start": "node dist/index.js",
16
- "dev": "tsx src/index.ts"
17
- },
18
- "keywords": [
19
- "zed",
20
- "zed-editor",
21
- "extension",
22
- "boilerplate",
23
- "scaffold"
24
- ],
25
- "author": "Taha Nejad <taha@noiserandom.com>",
26
- "repository": {
27
- "type": "git",
28
- "url": "https://github.com/tahayvr/zedx.git"
29
- },
30
- "homepage": "https://github.com/tahayvr/zedx#readme",
31
- "license": "Apache-2.0",
32
- "publishConfig": {
33
- "access": "public"
34
- },
35
- "engines": {
36
- "node": ">=18"
37
- },
38
- "devDependencies": {
39
- "@types/ejs": "^3.1.5",
40
- "@types/fs-extra": "^11.0.4",
41
- "@types/node": "^25.2.3",
42
- "tsx": "^4.21.0",
43
- "typescript": "^5.9.3"
44
- },
45
- "dependencies": {
46
- "@clack/prompts": "^0.10.1",
47
- "commander": "^14.0.3",
48
- "ejs": "^4.0.1",
49
- "fs-extra": "^11.3.3",
50
- "picocolors": "^1.1.1"
51
- },
52
- "packageManager": "pnpm@10.30.0+sha512.2b5753de015d480eeb88f5b5b61e0051f05b4301808a82ec8b840c9d2adf7748eb352c83f5c1593ca703ff1017295bc3fdd3119abb9686efc96b9fcb18200937"
2
+ "name": "zedx",
3
+ "version": "0.3.0",
4
+ "description": "Boilerplate generator for Zed Edittor extensions.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "zedx": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc && cp -r src/templates dist/",
15
+ "start": "node dist/index.js",
16
+ "dev": "tsx src/index.ts"
17
+ },
18
+ "keywords": [
19
+ "zed",
20
+ "zed-editor",
21
+ "extension",
22
+ "boilerplate",
23
+ "scaffold"
24
+ ],
25
+ "author": "Taha Nejad <taha@noiserandom.com>",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/tahayvr/zedx.git"
29
+ },
30
+ "homepage": "https://github.com/tahayvr/zedx#readme",
31
+ "license": "Apache-2.0",
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "devDependencies": {
39
+ "@types/ejs": "^3.1.5",
40
+ "@types/fs-extra": "^11.0.4",
41
+ "@types/node": "^25.2.3",
42
+ "tsx": "^4.21.0",
43
+ "typescript": "^5.9.3"
44
+ },
45
+ "dependencies": {
46
+ "@clack/prompts": "^0.10.1",
47
+ "commander": "^14.0.3",
48
+ "ejs": "^4.0.1",
49
+ "fs-extra": "^11.3.3",
50
+ "picocolors": "^1.1.1"
51
+ },
52
+ "packageManager": "pnpm@10.30.0+sha512.2b5753de015d480eeb88f5b5b61e0051f05b4301808a82ec8b840c9d2adf7748eb352c83f5c1593ca703ff1017295bc3fdd3119abb9686efc96b9fcb18200937"
53
53
  }