はじめに
前回の記事:
の補足をします。この記事ではスタイルについて触れませんでした。それをいじる方法についてです。
変更点
importmapにlezerを追加します。
<script type="importmap">
{
"imports": {
"@lezer/": "https://esm.sh/*@lezer/",
"codemirror/": "https://deno.land/x/codemirror_esm@v6.0.1/esm/"
}
}
</script>
このlezerというのは作者が開発してるスタイリング用のライブラリだそうです。これを導入することで、スタイリングに必要なタグを操作する機能が利用可能になります。これにより、demo.jsにおいてtagsをimportします。
import {tags} from "@lezer/highlight";
//console.log(Object.keys(tags));
このtagsに出てくる内容が色を変えられるタグのリストなんだそうです。ここから先は、次のサイトを参考にします。
これはimportmapの方法を紹介してる人のサイトが提供しているテーマになります。テーマ自体は直接importできるので、このテーマをそのまま使いたいのであればlezerは必要ありません。このサイトではlezerはnode_modulesという形で隠蔽されているので、直接その内容をいじることはできません...が、tagsがあれば、これをコピペして貼り付けることで、その内容をカスタマイズできるようになります。
import { HighlightStyle, syntaxHighlighting } from "codemirror/language/dist/index.js";
const palette = {
chalky:"#e5c07b",
coral:"#e06c75",
cyan:"#56b6c2",
invalid:"#ffffff",
ivory:"#abb2bf",
stone:"#7d8799",
malibu:"#61afef",
sage:"#98c379",
whiskey:"#d19a66",
violet:"#c678dd",
darkBackground:"#21252b",
highlightBackground:"#2c313a",
background:"#282c34",
tooltipBackground:"#353a42",
selection:"#3E4451",
cursor:"#528bff"
};
// lezerだけパクればいい。
import {tags} from "@lezer/highlight";
//console.log(Object.keys(tags));
const oneDarkTheme = /*@__PURE__*/EditorView.theme({
"&": {
color: palette.ivory,
backgroundColor: palette.background
},
".cm-content": {
caretColor: palette.cursor
},
".cm-cursor, .cm-dropCursor": { borderLeftColor: palette.cursor },
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { backgroundColor: palette.selection },
".cm-panels": { backgroundColor: palette.darkBackground, color: palette.ivory },
".cm-panels.cm-panels-top": { borderBottom: "2px solid black" },
".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" },
".cm-searchMatch": {
backgroundColor: "#72a1ff59",
outline: "1px solid #457dff"
},
".cm-searchMatch.cm-searchMatch-selected": {
backgroundColor: "#6199ff2f"
},
".cm-activeLine": { backgroundColor: "#6699ff0b" },
".cm-selectionMatch": { backgroundColor: "#aafe661a" },
"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
backgroundColor: "#bad0f847"
},
".cm-gutters": {
backgroundColor: palette.background,
color: palette.stone,
border: "none"
},
".cm-activeLineGutter": {
backgroundColor: palette.highlightBackground
},
".cm-foldPlaceholder": {
backgroundColor: "transparent",
border: "none",
color: "#ddd"
},
".cm-tooltip": {
border: "none",
backgroundColor: palette.tooltipBackground
},
".cm-tooltip .cm-tooltip-arrow:before": {
borderTopColor: "transparent",
borderBottomColor: "transparent"
},
".cm-tooltip .cm-tooltip-arrow:after": {
borderTopColor: palette.tooltipBackground,
borderBottomColor: palette.tooltipBackground
},
".cm-tooltip-autocomplete": {
"& > ul > li[aria-selected]": {
backgroundColor: palette.highlightBackground,
color: palette.ivory
}
}
}, { dark: true });
/**
The highlighting style for code in the One Dark theme.
*/
const oneDarkHighlightStyle = /*@__PURE__*/HighlightStyle.define([
{ tag: tags.keyword,
color: palette.violet },
{ tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName],
color: palette.coral },
{ tag: [/*@__PURE__*/tags.function(tags.variableName), tags.labelName],
color: palette.malibu },
{ tag: [tags.color, /*@__PURE__*/tags.constant(tags.name), /*@__PURE__*/tags.standard(tags.name)],
color: palette.whiskey },
{ tag: [/*@__PURE__*/tags.definition(tags.name), tags.separator],
color: palette.ivory },
{ tag: [tags.typeName, tags.className, tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace],
color: palette.chalky },
{ tag: [tags.operator, tags.operatorKeyword, tags.url, tags.escape, tags.regexp, tags.link, /*@__PURE__*/tags.special(tags.string)],
color: palette.cyan },
{ tag: [tags.meta, tags.comment],
color: palette.stone },
{ tag: tags.strong,
fontWeight: "bold" },
{ tag: tags.emphasis,
fontStyle: "italic" },
{ tag: tags.strikethrough,
textDecoration: "line-through" },
{ tag: tags.link,
color: palette.stone,
textDecoration: "underline" },
{ tag: tags.heading,
fontWeight: "bold",
color: palette.coral },
{ tag: [tags.atom, tags.bool, /*@__PURE__*/tags.special(tags.variableName)],
color: palette.whiskey },
{ tag: [tags.processingInstruction, tags.string, tags.inserted],
color: palette.sage },
{ tag: tags.invalid,
color: palette.invalid },
]);
const oneDark = [oneDarkTheme, /*@__PURE__*/syntaxHighlighting(oneDarkHighlightStyle)];
たとえばcommentの色を変えたい場合は次のようにします。現在、commentはstoneという色になっています。#7d8799ですね。
{ tag: [tags.meta, tags.comment],
color: palette.stone },
これを次のようにします。
{ tag: tags.meta,
color: palette.stone },
{ tag: tags.comment,
color: "aquamarine" },
すると見た目が次のように変化します。
無事、コメントの色を変えられました。こんな感じでカスタマイズできます。
補足:コピペの挙動について
ついでに注意を述べておきます。コピペのボタンを使って内容を取得する際、EditorStateを使う場合と使わない場合で書き方が異なる話を以前しましたが、実はStateを使わない場合、変な空行が入ってしまいます。それを防ぐために、基本的にEditorStateで書いた方がいいという話でした。そのように書き換えてあります。
navigator.clipboard.writeText(
view2.state.doc.toString()
//document.querySelector("#editor2").querySelector(".cm-content").innerText
).then(() => {
console.log("copied!");
});
おわりに
ここまでお読みいただいてありがとうございました。