logiguard fork: GPUI xdg-activation keyboard-focus serial fix
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled

Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree
with a 3-file patch applied (no upstream history).

Patch (crates/gpui_linux/src/linux/wayland/):
  - serial.rs: add SerialKind::KeyboardEnter
  - client.rs: store wl_keyboard.enter serial; add latest_serial_of()
  - window.rs: activate() uses keyboard-enter serial (Mutter focus gate)

Mutter honors window activation only when the token carries the keyboard-
focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial.
See docs/tray-window-focus-wayland.md in logiguard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mohamad Khani
2026-07-14 02:22:17 +03:30
co-authored by Claude Fable 5
commit b72a46db68
3984 changed files with 1583326 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
grammars
+181
View File
@@ -0,0 +1,181 @@
# Extracting an extension to dedicated repo
These are some notes of how to extract an extension from the main zed repository and generate a new repository which preserves the history as best as possible. In the this example we will be extracting the `ruby` extension, substitute as appropriate.
## Pre-requisites
Install [git-filter-repo](https://github.com/newren/git-filter-repo/blob/main/INSTALL.md):
```
brew install git-filter-repo
```
## Process
We are going to use a `$LANGNAME` variable for all these steps. Make sure it is set correctly.
> **Note**
> If you get `zsh: command not found: #` errors, run:
> `setopt interactive_comments && echo "setopt interactive_comments" >> ~/.zshrc`
1. Create a clean clone the zed repository, delete tags and delete branches.
```sh
LANGNAME=your_language_name_here
rm -rf $LANGNAME
git clone --single-branch --no-tags git@github.com:zed-industries/zed.git $LANGNAME
cd $LANGNAME
```
2. Create an expressions.txt file somewhere (e.g. `~/projects/$LANGNAME.txt`)
This file takes the form of `pattern==>replacement`, where the replacement is optional.
Note whitespace matters so `ruby: ==>` is removing the `ruby:` prefix from a commit messages and adding a space after `==> ` means the replacement begins with a space. Regex capture groups are numbered `\1`, `\2`, etc.
See: [Git Filter Repo Docs](https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html) for more.
```sh
# Create regex mapping for rewriting commit messages (edit as appropriate)
mkdir -p ~/projects
echo "${LANGNAME}: ==>
extension: ==>
chore: ==>
zed_extension_api: ==>
"'regex:(?<![\[a-zA-Z0-9])(#[0-9]{3,5})==>zed-industries/zed\1' \
> ~/projects/${LANGNAME}.txt
# This removes the LICENSE symlink
git filter-repo --invert-paths --path extensions/$LANGNAME/LICENSE-APACHE
# This does the work
git filter-repo \
--use-mailmap \
--subdirectory-filter extensions/$LANGNAME/ \
--path LICENSE-APACHE \
--replace-message ~/projects/${LANGNAME}.txt
```
3. Review the commits.
This is your last chance to make any modifications.
If you don't fix it now, it'll be wrong forever.
For example, a previous commit message was `php/ruby: bump version to 0.0.5`
which was replaced with `php/bump version to 0.0.5`
so I added a new line to expressions.txt with `php/==>`
and next run it became `bump version to 0.0.5`.
4. [Optional] Generate tags
You can always add tags later, but it's a nice touch.
Show you all commits that mention a version number:
```sh
git log --grep="(\d+\.\d+\.\d+)" --perl-regexp --oneline --reverse
```
Then just:
```
git tag v0.0.2 abcd1234
git tag v0.0.3 deadbeef
```
Usually the initial extraction didn't mention a version number so you can just do that one manually.
4. [Optional] Add a README.md and commit.
5. Push to the new repo
Create a new empty repo on github under the [zed-extensions](https://github.com/organizations/zed-extensions/repositories/new) organization.
```
git remote add origin git@github.com:zed-extensions/$LANGNAME
git push origin main --tags
git branch --set-upstream-to=origin/main main
```
6. Setup the new repository:
- Go to the repository settings:
- Disable Wikis
- Uncheck "Allow Merge Commits"
- Check "Allow Squash Merging"
- Default commit message: "Pull request title and description"
7. Publish a new version of the extension.
```sh
OLD_VERSION=$(grep '^version = ' extension.toml | cut -d'"' -f2)
NEW_VERSION=$(echo "$OLD_VERSION" | awk -F. '{$NF = $NF + 1;} 1' OFS=.)
echo $OLD_VERSION $NEW_VERSION
perl -i -pe "s/$OLD_VERSION/$NEW_VERSION/" extension.toml
perl -i -pe "s#https://github.com/zed-industries/zed#https://github.com/zed-extensions/${LANGNAME}#g" extension.toml
# if there's rust code, update this too.
test -f Cargo.toml && perl -i -pe "s/$OLD_VERSION/$NEW_VERSION/" Cargo.toml
# remove workspace Cargo.toml lines
test -f Cargo.toml && perl -ni -e 'print unless /^.*(workspace\s*=\s*true|\[lints\])\s*$/' Cargo.toml
test -f Cargo.toml && cargo check
# add a .gitignore
echo "target/
grammars/
*.wasm" > .gitignore
# commit and push
git add -u
git checkout -b "bump_${NEW_VERSION}"
git commit -m "Bump to v${NEW_VERSION}"
git push
gh pr create --title "Bump to v${NEW_VERSION}" --web
# merge PR in web interface
git checkout main
git pull
git tag v${NEW_VERSION}
git push origin v${NEW_VERSION}
```
7. In zed repository, remove the old extension and push a PR.
```sh
rm -rf extensions/$LANGNAME
sed -i '' "/extensions\/$LANGNAME/d" Cargo.toml
cargo check
git checkout -b remove_$LANGNAME
git add extensions/$LANGNAME
git add Cargo.toml Cargo.lock extensions/$LANGNAME
git commit -m "Migrate to $LANGNAME extension to zed-extensions/$LANGNAME"
git push
gh pr create --web
```
8. Update extensions repository:
```sh
cd ../extensions
git checkout main
git pull
git submodule init
git submodule update
git status
git checkout -b ${LANGNAME}_v${NEW_VERSION}
git submodule add https://github.com/zed-extensions/${LANGNAME}.git extensions/${LANGNAME}
pnpm sort-extensions
# edit extensions.toml:
# - bump version
# - change `submodule` from `extensions/zed` to new path
# - remove `path` line all together
git add extensions.toml .gitmodules extensions/${LANGNAME}
git diff --cached
git commit -m "Bump ${LANGNAME} to v${NEW_VERSION}"
git push
```
Create PR and reference the Zed PR with removal from tree.
+17
View File
@@ -0,0 +1,17 @@
# Zed Extensions
This directory contains extensions for Zed that are largely maintained by the Zed team. They currently live in the Zed repository for ease of maintenance.
If you are looking for the Zed extension registry, see the [`zed-industries/extensions`](https://github.com/zed-industries/extensions) repo.
## Structure
Currently, Zed includes support for a number of languages without requiring installing an extension. Those languages can be found under [`crates/languages/src`](https://github.com/zed-industries/zed/tree/main/crates/languages/src).
Support for all other languages is done via extensions. This directory ([extensions/](https://github.com/zed-industries/zed/tree/main/extensions/)) contains some of the officially maintained extensions. These extensions use the same [zed_extension_api](https://docs.rs/zed_extension_api/latest/zed_extension_api/) available to all [Zed Extensions](https://zed.dev/extensions) for providing [language servers](https://zed.dev/docs/extensions/languages#language-servers), [tree-sitter grammars](https://zed.dev/docs/extensions/languages#grammar) and [tree-sitter queries](https://zed.dev/docs/extensions/languages#tree-sitter-queries).
You can find the other officially maintained extensions in the [zed-extensions organization](https://github.com/zed-extensions).
## Dev Extensions
See the docs for [Developing an Extension Locally](https://zed.dev/docs/extensions/developing-extensions#developing-an-extension-locally) for how to work with one of these extensions.
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "zed_glsl"
version = "0.2.3"
edition.workspace = true
publish.workspace = true
license = "Apache-2.0"
[lints]
workspace = true
[lib]
path = "src/glsl.rs"
crate-type = ["cdylib"]
[dependencies]
zed_extension_api = "0.1.0"
+1
View File
@@ -0,0 +1 @@
../../LICENSE-APACHE
+15
View File
@@ -0,0 +1,15 @@
id = "glsl"
name = "GLSL"
description = "GLSL support."
version = "0.2.3"
schema_version = 1
authors = ["Mikayla Maki <mikayla@zed.dev>"]
repository = "https://github.com/zed-industries/zed"
[language_servers.glsl_analyzer]
name = "GLSL Analyzer LSP"
language = "GLSL"
[grammars.glsl]
repository = "https://github.com/theHamsta/tree-sitter-glsl"
commit = "31064ce53385150f894a6c72d61b94076adf640a"
@@ -0,0 +1,8 @@
("[" @open
"]" @close)
("{" @open
"}" @close)
("(" @open
")" @close)
@@ -0,0 +1,22 @@
name = "GLSL"
grammar = "glsl"
path_suffixes = [
# Traditional rasterization pipeline shaders
"vert", "frag", "tesc", "tese", "geom",
# Compute shaders
"comp",
# Mesh pipeline shaders
"task", "mesh",
# Ray tracing pipeline shaders
"rgen", "rint", "rahit", "rchit", "rmiss", "rcall",
# Other
"glsl"
]
first_line_pattern = '^#version \d+'
line_comments = ["// "]
block_comment = { start = "/* ", prefix = "* ", end = "*/", tab_size = 1 }
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true },
]
@@ -0,0 +1,129 @@
[
"break"
"case"
"const"
"continue"
"default"
"do"
"else"
"enum"
"extern"
"for"
"if"
"inline"
"return"
"sizeof"
"static"
"struct"
"switch"
"typedef"
"union"
"volatile"
"while"
"#define"
"#elif"
"#else"
"#endif"
"#if"
"#ifdef"
"#ifndef"
"#include"
(preproc_directive)
] @keyword
[
"--"
"-"
"-="
"->"
"="
"!="
"*"
"&"
"&&"
"+"
"++"
"+="
"<"
"=="
">"
"||"
"."
";"
] @operator
[
(string_literal)
(system_lib_string)
] @string
(null) @constant.builtin
[
(number_literal)
(char_literal)
] @number
(identifier) @variable
(field_identifier) @property
(statement_identifier) @label
[
(type_identifier)
(primitive_type)
(sized_type_specifier)
] @type
(call_expression
function: (identifier) @function)
(call_expression
function: (field_expression
field: (field_identifier) @function))
(function_declarator
declarator: (identifier) @function)
(preproc_function_def
name: (identifier) @function.special)
((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
(comment) @comment
[
"in"
"out"
"inout"
"uniform"
"shared"
"layout"
"attribute"
"varying"
"buffer"
"coherent"
"readonly"
"writeonly"
"precision"
"highp"
"mediump"
"lowp"
"centroid"
"sample"
"patch"
"smooth"
"flat"
"noperspective"
"invariant"
"precise"
] @type.qualifier
"subroutine" @keyword.function
(extension_storage_class) @storageclass
((identifier) @variable.builtin
(#match? @variable.builtin "^gl_"))
@@ -0,0 +1,2 @@
((comment) @injection.content
(#set! injection.language "comment"))
+131
View File
@@ -0,0 +1,131 @@
use std::fs;
use zed::settings::LspSettings;
use zed_extension_api::{self as zed, LanguageServerId, Result, serde_json};
struct GlslExtension {
cached_binary_path: Option<String>,
}
impl GlslExtension {
fn language_server_binary_path(
&mut self,
language_server_id: &LanguageServerId,
worktree: &zed::Worktree,
) -> Result<String> {
if let Some(path) = worktree.which("glsl_analyzer") {
return Ok(path);
}
if let Some(path) = &self.cached_binary_path
&& fs::metadata(path).is_ok_and(|stat| stat.is_file())
{
return Ok(path.clone());
}
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
);
let release = zed::latest_github_release(
"nolanderc/glsl_analyzer",
zed::GithubReleaseOptions {
require_assets: true,
pre_release: false,
},
)?;
let (platform, arch) = zed::current_platform();
let asset_name = format!(
"{arch}-{os}.zip",
arch = match arch {
zed::Architecture::Aarch64 => "aarch64",
zed::Architecture::X86 => "x86",
zed::Architecture::X8664 => "x86_64",
},
os = match platform {
zed::Os::Mac => "macos",
zed::Os::Linux => "linux-musl",
zed::Os::Windows => "windows",
}
);
let asset = release
.assets
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
let version_dir = format!("glsl_analyzer-{}", release.version);
fs::create_dir_all(&version_dir)
.map_err(|err| format!("failed to create directory '{version_dir}': {err}"))?;
let binary_path = format!("{version_dir}/bin/glsl_analyzer");
if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) {
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::Downloading,
);
zed::download_file(
&asset.download_url,
&version_dir,
match platform {
zed::Os::Mac | zed::Os::Linux => zed::DownloadedFileType::Zip,
zed::Os::Windows => zed::DownloadedFileType::Zip,
},
)
.map_err(|e| format!("failed to download file: {e}"))?;
zed::make_file_executable(&binary_path)?;
let entries =
fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
for entry in entries {
let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
if entry.file_name().to_str() != Some(&version_dir) {
fs::remove_dir_all(entry.path()).ok();
}
}
}
self.cached_binary_path = Some(binary_path.clone());
Ok(binary_path)
}
}
impl zed::Extension for GlslExtension {
fn new() -> Self {
Self {
cached_binary_path: None,
}
}
fn language_server_command(
&mut self,
language_server_id: &zed::LanguageServerId,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
Ok(zed::Command {
command: self.language_server_binary_path(language_server_id, worktree)?,
args: vec![],
env: Default::default(),
})
}
fn language_server_workspace_configuration(
&mut self,
_language_server_id: &zed::LanguageServerId,
worktree: &zed::Worktree,
) -> Result<Option<serde_json::Value>> {
let settings = LspSettings::for_worktree("glsl_analyzer", worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.settings)
.unwrap_or_default();
Ok(Some(serde_json::json!({
"glsl_analyzer": settings
})))
}
}
zed::register_extension!(GlslExtension);
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "zed_html"
version = "0.3.1"
edition.workspace = true
publish.workspace = true
license = "Apache-2.0"
[lints]
workspace = true
[lib]
path = "src/html.rs"
crate-type = ["cdylib"]
[dependencies]
zed_extension_api = "0.7.0"
+1
View File
@@ -0,0 +1 @@
../../LICENSE-APACHE
+19
View File
@@ -0,0 +1,19 @@
id = "html"
name = "HTML"
description = "HTML support."
version = "0.3.1"
schema_version = 1
authors = ["Isaac Clayton <slightknack@gmail.com>"]
repository = "https://github.com/zed-industries/zed"
[language_servers.vscode-html-language-server]
name = "vscode-html-language-server"
language = "HTML"
[language_servers.vscode-html-language-server.language_ids]
"HTML" = "html"
"CSS" = "css"
[grammars.html]
repository = "https://github.com/tree-sitter/tree-sitter-html"
commit = "bfa075d83c6b97cd48440b3829ab8d24a2319809"
@@ -0,0 +1,21 @@
(("<" @open
"/>" @close)
(#set! rainbow.exclude))
(("<" @open
">" @close)
(#set! rainbow.exclude))
(("</" @open
">" @close)
(#set! rainbow.exclude))
(("\"" @open
"\"" @close)
(#set! rainbow.exclude))
((element
(start_tag) @open
(end_tag) @close)
(#set! newline.only)
(#set! rainbow.exclude))
@@ -0,0 +1,19 @@
name = "HTML"
grammar = "html"
path_suffixes = ["html", "htm", "shtml"]
autoclose_before = ">})"
block_comment = { start = "<!--", prefix = "", end = "-->", tab_size = 0 }
wrap_characters = { start_prefix = "<", start_suffix = ">", end_prefix = "</", end_suffix = ">" }
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
{ start = "<", end = ">", close = false, newline = true, not_in = ["comment", "string"] },
{ start = "!--", end = " --", close = true, newline = false, not_in = ["comment", "string"] },
]
completion_query_characters = ["-"]
prettier_parser_name = "html"
[overrides.default]
linked_edit_characters = ["-"]
@@ -0,0 +1,25 @@
(tag_name) @tag
(doctype) @tag.doctype
(attribute_name) @attribute
[
"\""
"'"
(attribute_value)
] @string
(comment) @comment
(entity) @string.special
"=" @punctuation.delimiter.html
[
"<"
">"
"<!"
"</"
"/>"
] @punctuation.bracket.html
@@ -0,0 +1,9 @@
(start_tag
">" @end) @indent
(self_closing_tag
"/>" @end) @indent
(element
(start_tag) @start
(end_tag)? @end) @indent
@@ -0,0 +1,24 @@
((comment) @injection.content
(#set! injection.language "comment"))
(script_element
(raw_text) @injection.content
(#set! injection.language "javascript"))
(style_element
(raw_text) @injection.content
(#set! injection.language "css"))
(attribute
(attribute_name) @_attribute_name
(#match? @_attribute_name "^style$")
(quoted_attribute_value
(attribute_value) @injection.content)
(#set! injection.language "css"))
(attribute
(attribute_name) @_attribute_name
(#match? @_attribute_name "^on[a-z]+$")
(quoted_attribute_value
(attribute_value) @injection.content)
(#set! injection.language "javascript"))
@@ -0,0 +1,5 @@
(comment) @annotation
(element
(start_tag
(tag_name) @name)) @item
@@ -0,0 +1,8 @@
(comment) @comment
(quoted_attribute_value) @string
[
(start_tag)
(end_tag)
] @default
+112
View File
@@ -0,0 +1,112 @@
use std::{env, fs};
use zed::settings::LspSettings;
use zed_extension_api::{self as zed, LanguageServerId, Result, serde_json::json};
const BINARY_NAME: &str = "vscode-html-language-server";
const SERVER_PATH: &str =
"node_modules/@zed-industries/vscode-langservers-extracted/bin/vscode-html-language-server";
const PACKAGE_NAME: &str = "@zed-industries/vscode-langservers-extracted";
struct HtmlExtension {
cached_binary_path: Option<String>,
}
impl HtmlExtension {
fn server_exists(&self) -> bool {
fs::metadata(SERVER_PATH).is_ok_and(|stat| stat.is_file())
}
fn server_script_path(&mut self, language_server_id: &LanguageServerId) -> Result<String> {
let server_exists = self.server_exists();
if self.cached_binary_path.is_some() && server_exists {
return Ok(SERVER_PATH.to_string());
}
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
);
let version = zed::npm_package_latest_version(PACKAGE_NAME)?;
if !server_exists
|| zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version)
{
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::Downloading,
);
let result = zed::npm_install_package(PACKAGE_NAME, &version);
match result {
Ok(()) => {
if !self.server_exists() {
Err(format!(
"installed package '{PACKAGE_NAME}' did not contain expected path '{SERVER_PATH}'",
))?;
}
}
Err(error) => {
if !self.server_exists() {
Err(error)?;
}
}
}
}
Ok(SERVER_PATH.to_string())
}
}
impl zed::Extension for HtmlExtension {
fn new() -> Self {
Self {
cached_binary_path: None,
}
}
fn language_server_command(
&mut self,
language_server_id: &LanguageServerId,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
let server_path = if let Some(path) = worktree.which(BINARY_NAME) {
return Ok(zed::Command {
command: path,
args: vec!["--stdio".to_string()],
env: Default::default(),
});
} else {
let server_path = self.server_script_path(language_server_id)?;
env::current_dir()
.unwrap()
.join(&server_path)
.to_string_lossy()
.to_string()
};
self.cached_binary_path = Some(server_path.clone());
Ok(zed::Command {
command: zed::node_binary_path()?,
args: vec![server_path, "--stdio".to_string()],
env: Default::default(),
})
}
fn language_server_workspace_configuration(
&mut self,
server_id: &LanguageServerId,
worktree: &zed::Worktree,
) -> Result<Option<zed::serde_json::Value>> {
LspSettings::for_worktree(server_id.as_ref(), worktree)
.map(|lsp_settings| lsp_settings.settings)
}
fn language_server_initialization_options(
&mut self,
_server_id: &LanguageServerId,
_worktree: &zed_extension_api::Worktree,
) -> Result<Option<zed_extension_api::serde_json::Value>> {
let initialization_options = json!({"provideFormatter": true });
Ok(Some(initialization_options))
}
}
zed::register_extension!(HtmlExtension);
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "zed_proto"
version = "0.3.2"
edition.workspace = true
publish.workspace = true
license = "Apache-2.0"
[lints]
workspace = true
[lib]
path = "src/proto.rs"
crate-type = ["cdylib"]
[dependencies]
zed_extension_api = "0.7.0"
+1
View File
@@ -0,0 +1 @@
../../LICENSE-APACHE
+24
View File
@@ -0,0 +1,24 @@
id = "proto"
name = "Proto"
description = "Protocol Buffers support."
version = "0.3.2"
schema_version = 1
authors = ["Zed Industries <support@zed.dev>"]
repository = "https://github.com/zed-industries/zed"
[grammars.proto]
repository = "https://github.com/coder3101/tree-sitter-proto"
commit = "a6caac94b5aa36b322b5b70040d5b67132f109d0"
[language_servers.buf]
name = "Buf"
languages = ["Proto"]
[language_servers.protobuf-language-server]
name = "Protobuf Language Server"
languages = ["Proto"]
[language_servers.protols]
name = "Protols"
languages = ["Proto"]
@@ -0,0 +1,13 @@
name = "Proto"
grammar = "proto"
path_suffixes = ["proto"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
]
@@ -0,0 +1,62 @@
[
"syntax"
"package"
"option"
"optional"
"import"
"service"
"rpc"
"returns"
"message"
"enum"
"extend"
"oneof"
"repeated"
"reserved"
"to"
] @keyword
[
(key_type)
(type)
(message_name)
(enum_name)
(service_name)
(rpc_name)
(message_or_enum_type)
] @type
(enum_field
(identifier) @constant)
[
(string)
"\"proto3\""
] @string
(int_lit) @number
[
(true)
(false)
] @boolean
(comment) @comment
[
"("
")"
"["
"]"
"{"
"}"
"<"
">"
] @punctuation.bracket
[
";"
","
] @punctuation.delimiter
"=" @operator
@@ -0,0 +1,11 @@
(_
"{"
"}" @end) @indent
(_
"["
"]" @end) @indent
(_
"("
")" @end) @indent
@@ -0,0 +1,2 @@
((comment) @injection.content
(#set! injection.language "comment"))
@@ -0,0 +1,19 @@
(message
"message" @context
(message_name
(identifier) @name)) @item
(service
"service" @context
(service_name
(identifier) @name)) @item
(rpc
"rpc" @context
(rpc_name
(identifier) @name)) @item
(enum
"enum" @context
(enum_name
(identifier) @name)) @item
@@ -0,0 +1,22 @@
(message
(message_body
"{"
(_)* @class.inside
"}")) @class.around
(enum
(enum_body
"{"
(_)* @class.inside
"}")) @class.around
(service
"service"
(_)
"{"
(_)* @class.inside
"}") @class.around
(rpc) @function.around
(comment)+ @comment.around
+8
View File
@@ -0,0 +1,8 @@
mod buf;
mod protobuf_language_server;
mod protols;
mod util;
pub(crate) use buf::*;
pub(crate) use protobuf_language_server::*;
pub(crate) use protols::*;
@@ -0,0 +1,114 @@
use std::fs;
use zed_extension_api::{
self as zed, Architecture, DownloadedFileType, GithubReleaseOptions, Os, Result,
settings::LspSettings,
};
use crate::language_servers::util;
pub(crate) struct BufLsp {
cached_binary_path: Option<String>,
}
impl BufLsp {
pub(crate) const SERVER_NAME: &str = "buf";
pub(crate) fn new() -> Self {
BufLsp {
cached_binary_path: None,
}
}
pub(crate) fn language_server_binary(
&mut self,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
let binary_settings = LspSettings::for_worktree(Self::SERVER_NAME, worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.binary);
let args = binary_settings
.as_ref()
.and_then(|binary_settings| binary_settings.arguments.clone())
.unwrap_or_else(|| ["lsp", "serve"].map(ToOwned::to_owned).into());
if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) {
return Ok(zed::Command {
command: path,
args,
env: Default::default(),
});
} else if let Some(path) = self.cached_binary_path.clone() {
return Ok(zed::Command {
command: path,
args,
env: Default::default(),
});
} else if let Some(path) = worktree.which(Self::SERVER_NAME) {
self.cached_binary_path = Some(path.clone());
return Ok(zed::Command {
command: path,
args,
env: Default::default(),
});
}
let latest_release = zed::latest_github_release(
"bufbuild/buf",
GithubReleaseOptions {
require_assets: true,
pre_release: false,
},
)?;
let (os, arch) = zed::current_platform();
let release_suffix = match (os, arch) {
(Os::Mac, Architecture::Aarch64) => "Darwin-arm64",
(Os::Mac, Architecture::X8664) => "Darwin-x86_64",
(Os::Linux, Architecture::Aarch64) => "Linux-aarch64",
(Os::Linux, Architecture::X8664) => "Linux-x86_64",
(Os::Windows, Architecture::Aarch64) => "Windows-arm64.exe",
(Os::Windows, Architecture::X8664) => "Windows-x86_64.exe",
_ => {
return Err("Platform and architecture not supported by buf CLI".to_string());
}
};
let release_name = format!("buf-{release_suffix}");
let version_dir = format!("{}-{}", Self::SERVER_NAME, latest_release.version);
fs::create_dir_all(&version_dir).map_err(|_| "Could not create directory")?;
let binary_path = format!("{version_dir}/buf");
let download_target = latest_release
.assets
.into_iter()
.find(|asset| asset.name == release_name)
.ok_or_else(|| {
format!(
"Could not find asset with name {} in buf CLI release",
&release_name
)
})?;
zed::download_file(
&download_target.download_url,
&binary_path,
DownloadedFileType::Uncompressed,
)?;
zed::make_file_executable(&binary_path)?;
util::remove_outdated_versions(Self::SERVER_NAME, &version_dir)?;
self.cached_binary_path = Some(binary_path.clone());
Ok(zed::Command {
command: binary_path,
args,
env: Default::default(),
})
}
}
@@ -0,0 +1,52 @@
use zed_extension_api::{self as zed, Result, settings::LspSettings};
pub(crate) struct ProtobufLanguageServer {
cached_binary_path: Option<String>,
}
impl ProtobufLanguageServer {
pub(crate) const SERVER_NAME: &str = "protobuf-language-server";
pub(crate) fn new() -> Self {
ProtobufLanguageServer {
cached_binary_path: None,
}
}
pub(crate) fn language_server_binary(
&mut self,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
let binary_settings = LspSettings::for_worktree(Self::SERVER_NAME, worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.binary);
let args = binary_settings
.as_ref()
.and_then(|binary_settings| binary_settings.arguments.clone())
.unwrap_or_else(|| vec!["-logs".into(), "".into()]);
if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) {
Ok(zed::Command {
command: path,
args,
env: Default::default(),
})
} else if let Some(path) = self.cached_binary_path.clone() {
Ok(zed::Command {
command: path,
args,
env: Default::default(),
})
} else if let Some(path) = worktree.which(Self::SERVER_NAME) {
self.cached_binary_path = Some(path.clone());
Ok(zed::Command {
command: path,
args,
env: Default::default(),
})
} else {
Err(format!("{} not found in PATH", Self::SERVER_NAME))
}
}
}
@@ -0,0 +1,113 @@
use zed_extension_api::{
self as zed, Architecture, DownloadedFileType, GithubReleaseOptions, Os, Result,
settings::LspSettings,
};
use crate::language_servers::util;
pub(crate) struct ProtoLs {
cached_binary_path: Option<String>,
}
impl ProtoLs {
pub(crate) const SERVER_NAME: &str = "protols";
pub(crate) fn new() -> Self {
ProtoLs {
cached_binary_path: None,
}
}
pub(crate) fn language_server_binary(
&mut self,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
let binary_settings = LspSettings::for_worktree(Self::SERVER_NAME, worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.binary);
let args = binary_settings
.as_ref()
.and_then(|binary_settings| binary_settings.arguments.clone())
.unwrap_or_default();
let env = worktree.shell_env();
if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) {
return Ok(zed::Command {
command: path,
args,
env,
});
} else if let Some(path) = self.cached_binary_path.clone() {
return Ok(zed::Command {
command: path,
args,
env,
});
} else if let Some(path) = worktree.which(Self::SERVER_NAME) {
self.cached_binary_path = Some(path.clone());
return Ok(zed::Command {
command: path,
args,
env,
});
}
let latest_release = zed::latest_github_release(
"coder3101/protols",
GithubReleaseOptions {
require_assets: true,
pre_release: false,
},
)?;
let (os, arch) = zed::current_platform();
let release_suffix = match (os, arch) {
(Os::Mac, Architecture::Aarch64) => "aarch64-apple-darwin.tar.gz",
(Os::Mac, Architecture::X8664) => "x86_64-apple-darwin.tar.gz",
(Os::Linux, Architecture::Aarch64) => "aarch64-unknown-linux-gnu.tar.gz",
(Os::Linux, Architecture::X8664) => "x86_64-unknown-linux-gnu.tar.gz",
(Os::Windows, Architecture::X8664) => "x86_64-pc-windows-msvc.zip",
_ => {
return Err("Platform and architecture not supported by Protols".to_string());
}
};
let release_name = format!("protols-{release_suffix}");
let file_type = if os == Os::Windows {
DownloadedFileType::Zip
} else {
DownloadedFileType::GzipTar
};
let version_dir = format!("{}-{}", Self::SERVER_NAME, latest_release.version);
let binary_path = format!("{version_dir}/protols");
let download_target = latest_release
.assets
.into_iter()
.find(|asset| asset.name == release_name)
.ok_or_else(|| {
format!(
"Could not find asset with name {} in Protols release",
&release_name
)
})?;
zed::download_file(&download_target.download_url, &version_dir, file_type)?;
zed::make_file_executable(&binary_path)?;
util::remove_outdated_versions(Self::SERVER_NAME, &version_dir)?;
self.cached_binary_path = Some(binary_path.clone());
Ok(zed::Command {
command: binary_path,
args,
env,
})
}
}
@@ -0,0 +1,19 @@
use std::fs;
use zed_extension_api::Result;
pub(super) fn remove_outdated_versions(
language_server_id: &'static str,
version_dir: &str,
) -> Result<()> {
let entries = fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
for entry in entries {
let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
if entry.file_name().to_str().is_none_or(|file_name| {
file_name.starts_with(language_server_id) && file_name != version_dir
}) {
fs::remove_dir_all(entry.path()).ok();
}
}
Ok(())
}
+66
View File
@@ -0,0 +1,66 @@
use zed_extension_api::{self as zed, Result, settings::LspSettings};
use crate::language_servers::{BufLsp, ProtoLs, ProtobufLanguageServer};
mod language_servers;
struct ProtobufExtension {
protobuf_language_server: Option<ProtobufLanguageServer>,
protols: Option<ProtoLs>,
buf_lsp: Option<BufLsp>,
}
impl zed::Extension for ProtobufExtension {
fn new() -> Self {
Self {
protobuf_language_server: None,
protols: None,
buf_lsp: None,
}
}
fn language_server_command(
&mut self,
language_server_id: &zed_extension_api::LanguageServerId,
worktree: &zed_extension_api::Worktree,
) -> zed_extension_api::Result<zed_extension_api::Command> {
match language_server_id.as_ref() {
ProtobufLanguageServer::SERVER_NAME => self
.protobuf_language_server
.get_or_insert_with(ProtobufLanguageServer::new)
.language_server_binary(worktree),
ProtoLs::SERVER_NAME => self
.protols
.get_or_insert_with(ProtoLs::new)
.language_server_binary(worktree),
BufLsp::SERVER_NAME => self
.buf_lsp
.get_or_insert_with(BufLsp::new)
.language_server_binary(worktree),
_ => Err(format!("Unknown language server ID {}", language_server_id)),
}
}
fn language_server_workspace_configuration(
&mut self,
server_id: &zed::LanguageServerId,
worktree: &zed::Worktree,
) -> Result<Option<zed::serde_json::Value>> {
LspSettings::for_worktree(server_id.as_ref(), worktree)
.map(|lsp_settings| lsp_settings.settings)
}
fn language_server_initialization_options(
&mut self,
server_id: &zed::LanguageServerId,
worktree: &zed::Worktree,
) -> Result<Option<zed_extension_api::serde_json::Value>> {
LspSettings::for_worktree(server_id.as_ref(), worktree)
.map(|lsp_settings| lsp_settings.initialization_options)
}
}
zed::register_extension!(ProtobufExtension);
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "zed_test_extension"
version = "0.1.0"
edition.workspace = true
publish.workspace = true
license = "Apache-2.0"
[lints]
workspace = true
[lib]
path = "src/test_extension.rs"
crate-type = ["cdylib"]
[dependencies]
zed_extension_api = { path = "../../crates/extension_api" }
+1
View File
@@ -0,0 +1 @@
../../LICENSE-APACHE
+5
View File
@@ -0,0 +1,5 @@
# Test Extension
This is a test extension that we use in the tests for the `extension` crate.
Originally based off the Gleam extension.
+25
View File
@@ -0,0 +1,25 @@
id = "test-extension"
name = "Test Extension"
description = "An extension for use in tests."
version = "0.1.0"
schema_version = 1
authors = ["Marshall Bowers <elliott.codes@gmail.com>"]
repository = "https://github.com/zed-industries/zed"
[language_servers.gleam]
name = "Gleam LSP"
language = "Gleam"
[grammars.gleam]
repository = "https://github.com/gleam-lang/tree-sitter-gleam"
commit = "8432ffe32ccd360534837256747beb5b1c82fca1"
[[capabilities]]
kind = "process:exec"
command = "echo"
args = ["hello from a child process!"]
[[capabilities]]
kind = "process:exec"
command = "cmd"
args = ["/C", "echo", "hello from a child process!"]
@@ -0,0 +1,12 @@
name = "Gleam"
grammar = "gleam"
path_suffixes = ["gleam"]
line_comments = ["// ", "/// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string", "comment"] },
]
tab_size = 2
@@ -0,0 +1,162 @@
; Comments
(module_comment) @comment
(statement_comment) @comment
(comment) @comment
; Constants
(constant
name: (identifier) @constant)
; Variables
(identifier) @variable
(discard) @comment.unused
; Modules
(module) @module
(import
alias: (identifier) @module)
(remote_type_identifier
module: (identifier) @module)
(remote_constructor_name
module: (identifier) @module)
((field_access
record: (identifier) @module
field: (label) @function)
(#is-not? local))
; Functions
(unqualified_import
(identifier) @function)
(unqualified_import
"type"
(type_identifier) @type)
(unqualified_import
(type_identifier) @constructor)
(function
name: (identifier) @function)
(external_function
name: (identifier) @function)
(function_parameter
name: (identifier) @variable.parameter)
((function_call
function: (identifier) @function)
(#is-not? local))
((binary_expression
operator: "|>"
right: (identifier) @function)
(#is-not? local))
; "Properties"
; Assumed to be intended to refer to a name for a field; something that comes
; before ":" or after "."
; e.g. record field names, tuple indices, names for named arguments, etc
(label) @property
(tuple_access
index: (integer) @property)
; Attributes
(attribute
"@" @attribute
name: (identifier) @attribute)
(attribute_value
(identifier) @constant)
; Type names
(remote_type_identifier) @type
(type_identifier) @type
; Data constructors
(constructor_name) @constructor
; Literals
(string) @string
((escape_sequence) @warning
; Deprecated in v0.33.0-rc2:
(#eq? @warning "\\e"))
(escape_sequence) @string.escape
(bit_string_segment_option) @function.builtin
(integer) @number
(float) @number
; Reserved identifiers
; TODO: when tree-sitter supports `#any-of?` in the Rust bindings,
; refactor this to use `#any-of?` rather than `#match?`
((identifier) @warning
(#match? @warning "^(auto|delegate|derive|else|implement|macro|test|echo)$"))
; Keywords
[
(visibility_modifier) ; "pub"
(opacity_modifier) ; "opaque"
"as"
"assert"
"case"
"const"
; DEPRECATED: 'external' was removed in v0.30.
"external"
"fn"
"if"
"import"
"let"
"panic"
"todo"
"type"
"use"
] @keyword
; Operators
(binary_expression
operator: _ @operator)
(boolean_negation
"!" @operator)
(integer_negation
"-" @operator)
; Punctuation
[
"("
")"
"["
"]"
"{"
"}"
"<<"
">>"
] @punctuation.bracket
[
"."
","
; Controversial -- maybe some are operators?
":"
"#"
"="
"->"
".."
"-"
"<-"
] @punctuation.delimiter
@@ -0,0 +1,11 @@
(_
"["
"]" @end) @indent
(_
"{"
"}" @end) @indent
(_
"("
")" @end) @indent
@@ -0,0 +1,31 @@
(external_type
(visibility_modifier)? @context
"type" @context
(type_name) @name) @item
(type_definition
(visibility_modifier)? @context
(opacity_modifier)? @context
"type" @context
(type_name) @name) @item
(data_constructor
(constructor_name) @name) @item
(data_constructor_argument
(label) @name) @item
(type_alias
(visibility_modifier)? @context
"type" @context
(type_name) @name) @item
(function
(visibility_modifier)? @context
"fn" @context
name: (_) @name) @item
(constant
(visibility_modifier)? @context
"const" @context
name: (_) @name) @item
@@ -0,0 +1,209 @@
use std::fs;
use zed::lsp::CompletionKind;
use zed::{CodeLabel, CodeLabelSpan, LanguageServerId};
use zed_extension_api::process::Command;
use zed_extension_api::{self as zed, Result};
struct TestExtension {
cached_binary_path: Option<String>,
}
impl TestExtension {
fn language_server_binary_path(
&mut self,
language_server_id: &LanguageServerId,
_worktree: &zed::Worktree,
) -> Result<String> {
let (platform, arch) = zed::current_platform();
let current_dir = std::env::current_dir().unwrap();
println!("current_dir: {}", current_dir.display());
assert_eq!(
current_dir.file_name().unwrap().to_str().unwrap(),
"test-extension"
);
fs::create_dir_all(current_dir.join("dir-created-with-abs-path")).unwrap();
fs::create_dir_all("./dir-created-with-rel-path").unwrap();
fs::write("file-created-with-rel-path", b"contents 1").unwrap();
fs::write(
current_dir.join("file-created-with-abs-path"),
b"contents 2",
)
.unwrap();
assert_eq!(
fs::read("file-created-with-rel-path").unwrap(),
b"contents 1"
);
assert_eq!(
fs::read("file-created-with-abs-path").unwrap(),
b"contents 2"
);
let command = match platform {
zed::Os::Linux | zed::Os::Mac => Command::new("echo"),
zed::Os::Windows => Command::new("cmd").args(["/C", "echo"]),
};
let output = command.arg("hello from a child process!").output()?;
println!(
"command output: {}",
String::from_utf8_lossy(&output.stdout).trim()
);
if let Some(path) = &self.cached_binary_path
&& fs::metadata(path).is_ok_and(|stat| stat.is_file())
{
return Ok(path.clone());
}
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
);
let release = zed::latest_github_release(
"gleam-lang/gleam",
zed::GithubReleaseOptions {
require_assets: true,
pre_release: false,
},
)?;
let ext = "tar.gz";
let download_type = zed::DownloadedFileType::GzipTar;
// Do this if you want to actually run this extension -
// the actual asset is a .zip. But the integration test is simpler
// if every platform uses .tar.gz.
//
// ext = "zip";
// download_type = zed::DownloadedFileType::Zip;
let asset_name = format!(
"gleam-{version}-{arch}-{os}.{ext}",
version = release.version,
arch = match arch {
zed::Architecture::Aarch64 => "aarch64",
zed::Architecture::X86 => "x86",
zed::Architecture::X8664 => "x86_64",
},
os = match platform {
zed::Os::Mac => "apple-darwin",
zed::Os::Linux => "unknown-linux-musl",
zed::Os::Windows => "pc-windows-msvc",
},
);
let asset = release
.assets
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
let version_dir = format!("gleam-{}", release.version);
let binary_path = format!("{version_dir}/gleam");
if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) {
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::Downloading,
);
zed::download_file(&asset.download_url, &version_dir, download_type)
.map_err(|e| format!("failed to download file: {e}"))?;
zed::set_language_server_installation_status(
language_server_id,
&zed::LanguageServerInstallationStatus::None,
);
let entries =
fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
for entry in entries {
let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
let filename = entry.file_name();
let filename = filename.to_str().unwrap();
if filename.starts_with("gleam-") && filename != version_dir {
fs::remove_dir_all(entry.path()).ok();
}
}
}
self.cached_binary_path = Some(binary_path.clone());
Ok(binary_path)
}
}
impl zed::Extension for TestExtension {
fn new() -> Self {
Self {
cached_binary_path: None,
}
}
fn language_server_command(
&mut self,
language_server_id: &LanguageServerId,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
Ok(zed::Command {
command: self.language_server_binary_path(language_server_id, worktree)?,
args: vec!["lsp".to_string()],
env: Default::default(),
})
}
fn label_for_completion(
&self,
_language_server_id: &LanguageServerId,
completion: zed::lsp::Completion,
) -> Option<zed::CodeLabel> {
let name = &completion.label;
let ty = strip_newlines_from_detail(&completion.detail?);
let let_binding = "let a";
let colon = ": ";
let assignment = " = ";
let call = match completion.kind? {
CompletionKind::Function | CompletionKind::Constructor => "()",
_ => "",
};
let code = format!("{let_binding}{colon}{ty}{assignment}{name}{call}");
Some(CodeLabel {
spans: vec![
CodeLabelSpan::code_range({
let start = let_binding.len() + colon.len() + ty.len() + assignment.len();
start..start + name.len()
}),
CodeLabelSpan::code_range({
let start = let_binding.len();
start..start + colon.len()
}),
CodeLabelSpan::code_range({
let start = let_binding.len() + colon.len();
start..start + ty.len()
}),
],
filter_range: (0..name.len()).into(),
code,
})
}
}
zed::register_extension!(TestExtension);
/// Removes newlines from the completion detail.
///
/// The Gleam LSP can return types containing newlines, which causes formatting
/// issues within the Zed completions menu.
fn strip_newlines_from_detail(detail: &str) -> String {
let without_newlines = detail
.replace("->\n ", "-> ")
.replace("\n ", "")
.replace(",\n", "");
let comma_delimited_parts = without_newlines.split(',');
comma_delimited_parts
.map(|part| part.trim())
.collect::<Vec<_>>()
.join(", ")
}
+21
View File
@@ -0,0 +1,21 @@
# Generated from xtask::workflows::extensions::run_tests within the Zed repository.
# Rebuild with `cargo xtask workflows`.
name: extensions::run_tests
on:
pull_request:
branches:
- '**'
push:
branches:
- main
jobs:
call_extension_tests:
permissions:
contents: read
uses: zed-industries/zed/.github/workflows/extension_tests.yml@main
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}pr
cancel-in-progress: true
defaults:
run:
shell: bash -euxo pipefail {0}
@@ -0,0 +1,61 @@
# Generated from xtask::workflows::extensions::bump_version within the Zed repository.
# Rebuild with `cargo xtask workflows`.
name: extensions::bump_version
on:
pull_request:
types:
- labeled
push:
branches:
- main
paths-ignore:
- .github/**
workflow_dispatch: {}
jobs:
determine_bump_type:
if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions')
runs-on: namespace-profile-2x4-ubuntu-2404
permissions: {}
steps:
- id: get-bump-type
name: extensions::bump_version::get_bump_type
run: |
if [ "$HAS_MAJOR_LABEL" = "true" ]; then
bump_type="major"
elif [ "$HAS_MINOR_LABEL" = "true" ]; then
bump_type="minor"
else
bump_type="patch"
fi
echo "bump_type=$bump_type" >> $GITHUB_OUTPUT
env:
HAS_MAJOR_LABEL: |-
${{ (github.event.action == 'labeled' && github.event.label.name == 'major') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'major')) }}
HAS_MINOR_LABEL: |-
${{ (github.event.action == 'labeled' && github.event.label.name == 'minor') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'minor')) }}
outputs:
bump_type: ${{ steps.get-bump-type.outputs.bump_type }}
call_bump_version:
needs:
- determine_bump_type
if: github.event.action != 'labeled' || needs.determine_bump_type.outputs.bump_type != 'patch'
permissions:
actions: write
contents: write
issues: write
pull-requests: write
uses: zed-industries/zed/.github/workflows/extension_bump.yml@main
secrets:
app-id: ${{ secrets.ZED_ZIPPY_APP_ID }}
app-secret: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }}
with:
bump-type: ${{ needs.determine_bump_type.outputs.bump_type }}
force-bump: ${{ github.event_name != 'push' }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}labels
cancel-in-progress: true
defaults:
run:
shell: bash -euxo pipefail {0}