Skip to content

Instantly share code, notes, and snippets.

@tynanbe
Created November 7, 2023 23:03
Show Gist options
  • Save tynanbe/dc10df454257606533abdeb145ddeeed to your computer and use it in GitHub Desktop.
Save tynanbe/dc10df454257606533abdeb145ddeeed to your computer and use it in GitHub Desktop.
POSIX shell scripts and Helix config to auto-select when to use Deno, TS LS, and/or Prettier for the current file. Bonus script to auto-update Helix grammars.
#!/bin/sh
#
# Runs `deno lsp` if a Deno configuration file is found, otherwise runs
# `typescript-language-server`
#
# Usage: deno_lsp_or_tsls ...[arguments]
#
# This script is intended to be run by the Helix editor, or any other editor
# that includes the current buffer's filename as the final field in its process
# command line.
#
set -e
PATH="$(dirname "$(realpath "${0}")"):${PATH}"
file=$(
ps -p "${PPID}" -o "command=" \
| awk '{ print $NF }'
)
prev=""
dir=$(dirname "$(realpath "${file}")")
cd "${dir}"
file=$(basename "${file}")
should_deno_lsp() (
case "${dir}" in
"${prev}") return 1 ;;
*)
if test -r "deno.json" \
-o -r "deno.jsonc"; then
return 0
elif test -r "package.json"; then
return 1
else
cd ..
prev="${dir}"
dir=$(pwd)
should_deno_lsp
fi
;;
esac
)
if should_deno_lsp; then
if qtype deno; then
exec deno lsp --unstable "${@}"
fi
elif qtype typescript-language-server; then
exec typescript-language-server --stdio "${@}"
fi
exit 1
#!/bin/sh
#
# Updates Helix grammars defined in `${XDG_CONFIG_HOME}/helix/languages.toml` if
# any new revisions are found
#
# Usage: hx_grammars
#
# All grammars are compiled, but only those specified in `languages.toml` are
# retained.
#
set -e
PATH="$(dirname "$(realpath "${0}")"):${PATH}"
qtype git hx jq toml
helix_dir="${XDG_CONFIG_HOME}/helix"
grammars_dir="${helix_dir}/runtime/grammars"
languages="${helix_dir}/languages.toml"
# Get latest git revisions for grammars defined in `${languages}`
#
grammar_names=""
do_update="False"
grammars=$(
toml get "${languages}" grammar \
| jq '.[] | "name=\"\(.name)\";repo=\"\(.source.git)\";current_revision=\"\(.source.rev)\""' --raw-output
)
cd "/tmp/"
for grammar in ${grammars}; do
name="None"
repo="None"
current_revision="None"
eval "${grammar}"
case "${name}${repo}${current_revision}" in
*None*) continue ;;
esac
grammar_names=$(
case "${grammar_names}" in
"") echo "${name}" ;;
*) echo "${grammar_names}" "${name}" ;;
esac
)
repo_dir=$(basename "${repo}")
echo "Searching for ${name} grammar updates..."
git clone --depth=1 --quiet "${repo}.git"
cd "${repo_dir}"
new_revision=$(git rev-parse HEAD)
cd "/tmp/"
rm -rf "${repo_dir}"
case "${new_revision}" in
"${current_revision}") continue ;;
*)
do_update="True"
sed -i "s/${current_revision}/${new_revision}/" "${languages}"
;;
esac
done
# Update compiled grammars if needed
#
case "${do_update}" in
True) echo "Compiling new grammars..." ;;
False)
echo "No new grammars found"
exit 0
;;
esac
for action in fetch build; do
hx --grammar "${action}" >/dev/null
done
rm -rf "${grammars_dir}/sources/"
for grammar in ${grammar_names}; do
cp "${grammars_dir}/${grammar}.so" "/tmp/"
done
rm -rf "${grammars_dir}"
mkdir -p "${grammars_dir}"
for grammar in ${grammar_names}; do
mv "/tmp/${grammar}.so" "${grammars_dir}/"
done
echo "Grammars updated"
exit 0
[[language]]
name = "bash"
auto-format = true
[language.formatter]
command = "shfmt"
args = [
"--binary-next-line",
"--case-indent",
"--indent=2",
"--simplify",
]
[[language]]
name = "elixir"
auto-format = true
[[grammar]]
name = "elixir"
[grammar.source]
git = "https://github.com/elixir-lang/tree-sitter-elixir"
rev = "a2861e88a730287a60c11ea9299c033c7d076e30"
[[language]]
name = "erlang"
auto-format = true
[[grammar]]
name = "erlang"
[grammar.source]
git = "https://github.com/the-mikedavis/tree-sitter-erlang"
rev = "bf56054c7c1bc66a27552b19702ffac8189ac7ec"
[[language]]
name = "gleam"
auto-format = true
formatter = { command = "gleam", args = ["format", "--stdin"] }
[[grammar]]
name = "gleam"
[grammar.source]
git = "https://github.com/gleam-lang/tree-sitter-gleam"
rev = "399172f660160258ede7d8e1d769f7fc5f61ff33"
[[language]]
name = "javascript"
auto-format = true
formatter = { command = "prettier_or_deno_fmt" }
language-servers = ["deno-lsp-or-tsls"]
[[language]]
name = "json"
auto-format = true
formatter = { command = "prettier_or_deno_fmt" }
[[language]]
name = "markdown"
auto-format = true
formatter = { command = "prettier_or_deno_fmt" }
[[language]]
name = "php"
indent = { tab-width = 2, unit = "\t" }
[[language]]
name = "sql"
auto-format = true
formatter = { command = "prettier", args = ["--stdin-filepath=query.sql", "--config-precedence=file-override", "--sql-keyword-case=lower"] }
[[language]]
name = "typescript"
auto-format = true
formatter = { command = "prettier_or_deno_fmt" }
language-servers = ["deno-lsp-or-tsls"]
[language-server.deno-lsp-or-tsls]
command = "deno_lsp_or_tsls"
environment = { NO_COLOR = "1" }
config.hostInfo = "helix"
[language-server.deno-lsp-or-tsls.config.deno]
enable = true
unstable = true
cacheOnSave = true
suggest = { completeFunctionCalls = false, imports = { hosts = { "https://deno.land" = true } } }
# suggest = { completeFunctionCalls = false, imports = { hosts = { "https://deno.land" = true, "https://crux.land" = true, "https://x.nest.land" = true } } }
inlayHints.parameterNames.enabled = "all"
inlayHints.parameterTypes.enabled = true
inlayHints.variableTypes.enabled = true
inlayHints.propertyDeclarationTypes.enabled = true
inlayHints.functionLikeReturnTypes.enabled = true
inlayHints.enumMemberValues.enabled = true
[language-server.deno-lsp-or-tsls.config.typescript.inlayHints]
includeInlayEnumMemberValueHints = true
includeInlayFunctionLikeReturnTypeHints = true
includeInlayFunctionParameterTypeHints = true
includeInlayParameterNameHints = "all"
includeInlayParameterNameHintsWhenArgumentMatchesName = true
includeInlayPropertyDeclarationTypeHints = true
includeInlayVariableTypeHints = true
[language-server.deno-lsp-or-tsls.config.javascript.inlayHints]
includeInlayEnumMemberValueHints = true
includeInlayFunctionLikeReturnTypeHints = true
includeInlayFunctionParameterTypeHints = true
includeInlayParameterNameHints = "all"
includeInlayParameterNameHintsWhenArgumentMatchesName = true
includeInlayPropertyDeclarationTypeHints = true
includeInlayVariableTypeHints = true
#!/bin/sh
#
# Formats stdin using Prettier if a configuration file is found, otherwise uses
# the Deno formatter
#
# Usage: prettier_or_deno_fmt
#
# This script is intended to be run by the Helix editor, or any other editor
# that includes the current buffer's filename as the final field in its process
# command line.
#
set -e
PATH="$(dirname "$(realpath "${0}")"):${PATH}"
file=$(
ps -p "${PPID}" -o "command=" \
| awk '{ print $NF }'
)
prev=""
dir=$(dirname "$(realpath "${file}")")
cd "${dir}"
file=$(basename "${file}")
should_prettier() (
case "${dir}" in
"${prev}") return 1 ;;
*)
if grep -iqs "prettier" "package.json" \
|| test -r ".prettierrc" \
-o -r ".prettierrc.json" \
-o -r ".prettierrc.yml" \
-o -r ".prettierrc.yaml" \
-o -r ".prettierrc.json5" \
-o -r ".prettierrc.js" \
-o -r ".prettierrc.cjs" \
-o -r "prettier.config.js" \
-o -r "prettier.config.cjs" \
-o -r ".prettierrc.toml"; then
return 0
elif test -r "deno.json" \
-o -r "deno.jsonc"; then
return 1
else
cd ..
prev="${dir}"
dir=$(pwd)
should_prettier
fi
;;
esac
)
if should_prettier; then
if qtype prettier; then
exec prettier \
--loglevel=silent \
--stdin-filepath="${file}"
fi
elif qtype deno; then
case "${file}" in
.*.*) ext="${file##*.}" ;;
.*) ext="" ;;
*.*) ext="${file##*.}" ;;
*) ext="" ;;
esac
exec deno fmt \
--ext="${ext}" \
--quiet \
--unstable \
-
fi
exit 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment