My Memo

← Back to posts

Elvish syntax highlighter

· elvish, shiki

Background

最近戯れに Elvish を使っている。

といった点が気に入っている。

ただ、色々なエディタのSyntax highlighterでサポートされていないことが多かった。

Investigation

既存のSyntax Highlighterもいくつかは存在している。

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

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

ちょっと眠すぎるので、これ以上の深堀はせずに、今日はもう寝ます