Elvish syntax highlighter
Background
最近戯れに Elvish を使っている。
- 入力時にSyntax highlightが入ってナウい
- zoxide的なフォルダへのジャンプ機能が充実している
- 構造化データをやり取りできる
- 既に割と安定している
といった点が気に入っている。
ただ、色々なエディタのSyntax highlighterでサポートされていないことが多かった。
Investigation
既存のSyntax Highlighterもいくつかは存在している。
- VS CodeのExtension はメインのレポジトリで開発されている模様。ElvishのLSPと連携するっぽい?
- その他いくつか。ただ、どれも結構前に更新が止まっている
Implementation
Syntax Highlightの実装にあたっては、TextMateの形式が広く使われているらしい。
こんなかんじのJSON形式で、正規表現でパースするルールと、構成要素に名前をつけていく。これをいい感じにレンダリングしている。
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Elvish",
"scopeName": "source.elvish",
"fileTypes": [
"elv"
],
"patterns": [
{
"name": "string.quoted.double.elvish",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.elvish",
"match": "\\\\."
}
]
},
// ...
],
// ...
}
このルールを準備しておけば、色々な仕組みに組み込んでいけるようになる。
ちなみに、元々Elvishでは以下のような形で関数を定義していた。
fn foo [param &opt=1] {
# function body
}
これのせいで、正規表現ベースだと [ の後に続くものが関数のパラメータなのか配列なのか判断することが出来なかった (issue#664)。
これを受けて関数の定義が fn foo {|param &opt| ... } のような形に 変更されている。公式レポジトリのもの以外、ざっと調べた限りこの変更の前に更新が止まってしまっている。
Obsidian x Shiki
- そもそものSyntax highlightのプラグインとしてShiki highlighterを導入してみた。
- これが導入されていれば、自前で設定したSyntaxを用いてHighlightさせられる
- 設定からGrammarファイルおいた場所を指定するだけ
Astro x Shiki
Astroでも、同じようにTextMate形式のGrammar定義があれば、これを追加できる。
Reults
以下のようにハイライトできるようになった!
use os
use path
# Virtualenv
var possible_virtualenv_dirs = [.venv venv .virtualenv]
var is_in_virtualenv = $false
var previous_paths = $nil
var venv = $nil
fn activate-virtualenv {|target_dir|
if $is_in_virtualenv {
echo "Already in virtualenv"
return
}
var venv = (path:abs $target_dir)
set-env VIRTUAL_ENV $venv
set previous_paths = $paths
set paths = [$venv/bin $venv/Scripts $@paths]
set is_in_virtualenv = $true
}
edit:add-var activate-virtualenv~ $activate-virtualenv~
fn deactivate-virtualenv {
if $is_in_virtualenv {
set paths = $previous_paths
set venv = $nil
set-env VIRTUAL_ENV ""
set is_in_virtualenv = $false
} else {
echo "Not in virtualenv"
}
}
edit:add-var deactivate-virtualenv~ $deactivate-virtualenv~
fn enter-virtualenv {|&target_dir=""|
if (eq $target_dir "") {
for dir $possible_virtualenv_dirs {
if (os:exists $dir) {
activate-virtualenv $dir
return
}
}
echo "No virtualenv found"
} else {
activate-virtualenv $target_dir
}
}
edit:add-var enter-virtualenv~ $enter-virtualenv~
Misc
ちょっと眠すぎるので、これ以上の深堀はせずに、今日はもう寝ます