diff --git a/package.json b/package.json
index 112f17e..8d95e00 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "TechTerm",
"private": true,
- "version": "0.1.1",
+ "version": "0.2.1",
"workspaces": [
"packages/core",
"packages/vscode",
diff --git a/packages/browser/manifest.json b/packages/browser/manifest.json
index 1e0a37d..d450d81 100644
--- a/packages/browser/manifest.json
+++ b/packages/browser/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "TechTerm",
- "version": "0.1.1",
+ "version": "0.2.1",
"description": "プログラミング用語にホバーすると、意味を簡潔に表示します。",
"content_scripts": [
{
diff --git a/packages/browser/package.json b/packages/browser/package.json
index 865c587..562184e 100644
--- a/packages/browser/package.json
+++ b/packages/browser/package.json
@@ -1,6 +1,6 @@
{
"name": "@techword/browser",
- "version": "0.1.1",
+ "version": "0.2.1",
"private": true,
"typescript": "^6.0.3",
"scripts": {
diff --git a/packages/browser/src/content.ts b/packages/browser/src/content.ts
index e08afb2..a3073a9 100644
--- a/packages/browser/src/content.ts
+++ b/packages/browser/src/content.ts
@@ -2,6 +2,16 @@ import { Dictionary, builtinTerms, type Match } from '@techword/core';
const dictionary = new Dictionary(builtinTerms);
+installHighlightStyle();
+highlight();
+const observer = new MutationObserver(highlight);
+const config = {
+ childList: true, // 子要素の追加・削除を監視
+ subtree: true, // 子孫要素(さらに下の階層)まで含めて監視する場合に true
+ characterData: true, // テキストノードの変更を監視
+};
+observer.observe(document.body, config);
+
/** ホバーしてから出すまでの待ち時間。すぐ出すとポインタを動かすたびに点滅する。 */
const HOVER_DELAY_MS = 250;
@@ -17,6 +27,7 @@ document.addEventListener('scroll', hide, { passive: true, capture: true });
window.addEventListener('blur', hide);
function handleHover(event: MouseEvent): void {
+ if (tooltip.host.style.display === 'block' && tooltip.host.matches(':hover')) return; // ツールチップ上にマウスがあるときはツールチップを消さないようにする
const caret = caretFromPoint(event.clientX, event.clientY);
if (!caret || caret.node.nodeType !== Node.TEXT_NODE) return hide();
@@ -140,3 +151,34 @@ function caretFromPoint(x: number, y: number): { node: Node; offset: number } |
return undefined;
}
+
+function highlight(): void {
+ let ranges: Range[] = [];
+ const walker = document.createTreeWalker(
+ document.body, // body以下のノードを走査する
+ NodeFilter.SHOW_TEXT, //テキストノードのみを対象
+ );
+
+ while (walker.nextNode() !== null) {
+ const nodeTagName = walker.currentNode.parentElement?.tagName;
+ if (nodeTagName === 'SCRIPT' || nodeTagName === 'STYLE') continue; // 負荷軽減のためにスクリプトとスタイルの中身は無視する
+ const textNodes = dictionary.findAll(walker.currentNode.textContent ?? '');
+ for (const {start, end} of textNodes) {
+ const range = new Range();
+ range.setStart(walker.currentNode, start);
+ range.setEnd(walker.currentNode, end);
+ ranges.push(range);
+ }
+ }
+ const highlightRange = new Highlight(...ranges); //スプレッド構文でranges配列を展開し引数として渡す
+ CSS.highlights.set("tw-highlight", highlightRange);
+}
+
+function installHighlightStyle(): void {
+ const style = document.createElement("style");
+ style.textContent = `
+ ::highlight(tw-highlight) {
+ background-color: #ffff00;
+ }`;
+ document.head.append(style);
+}
diff --git a/packages/core/package.json b/packages/core/package.json
index 10414c8..28d2d7b 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@techword/core",
- "version": "0.1.1",
+ "version": "0.2.1",
"private": true,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
diff --git a/packages/core/src/data/terms.json b/packages/core/src/data/terms.json
index 4721bc8..86c7ba5 100644
--- a/packages/core/src/data/terms.json
+++ b/packages/core/src/data/terms.json
@@ -210,6 +210,434 @@
"match": ["リファクタリング", "リファクタ"],
"short": "動作を変えずに、コードを読みやすく整理すること。",
"detail": "重複した処理をまとめたり、分かりにくい名前を直したりする。機能追加ではなく、今後の修正や開発をしやすくするために行う。"
+ },
+ {
+ "id": "object",
+ "term": "object",
+ "match": ["オブジェクト"],
+ "short": "複数のデータや処理をひとまとまりにしたもの。",
+ "detail": "JavaScript では、キーとバリューの組み合わせで情報を持つデータ構造。配列や関数もオブジェクトの一種として扱われる。",
+ "example": "const user = { name: 'Aki', age: 20 };",
+ "link": "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object"
+ },
+ {
+ "id": "class",
+ "term": "class",
+ "match": ["クラス"],
+ "short": "同じ種類のオブジェクトを作るための設計図。",
+ "detail": "持たせるデータや使える処理をまとめて定義する。JavaScript では new と一緒に使うことで、クラスからインスタンスを作れる。",
+ "example": "class User { constructor(name) { this.name = name; } }",
+ "link": "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes"
+ },
+ {
+ "id": "instance",
+ "term": "instance",
+ "match": ["インスタンス"],
+ "short": "クラスなどの設計をもとに実際に作られたオブジェクト。",
+ "detail": "同じクラスから複数作ることができ、それぞれが別のデータを持つ。JavaScript では new を使って作るのが代表的。",
+ "example": "const user = new User('Aki');"
+ },
+ {
+ "id": "key",
+ "term": "key",
+ "match": ["キー", "property name", "プロパティ名"],
+ "short": "オブジェクトなどから値を取り出すための名前。",
+ "detail": "JavaScript のオブジェクトでは、キーとバリューを組み合わせてデータを持つ。たとえば user.name の name がキーにあたる。",
+ "example": "const user = { name: 'Aki' };"
+ },
+ {
+ "id": "value",
+ "term": "value",
+ "match": ["バリュー", "値"],
+ "short": "変数やキーに対応して保存されているデータ。",
+ "detail": "文字列、数値、真偽値、オブジェクト、関数など、プログラムで扱う具体的な中身を指す。たとえば { name: 'Aki' } では 'Aki' がバリュー。",
+ "example": "const answer = 42;"
+ },
+ {
+ "id": "path",
+ "term": "path",
+ "match": ["パス", "ファイルパス"],
+ "short": "ファイルやディレクトリの場所を表す文字列。",
+ "detail": "ルートディレクトリから示す絶対パスと、カレントディレクトリなどを基準に示す相対パスがある。OS によって区切り文字が異なる。",
+ "example": "./src/index.js"
+ },
+ {
+ "id": "directory",
+ "term": "directory",
+ "match": ["ディレクトリ", "folder", "フォルダ"],
+ "short": "ファイルや別のディレクトリをまとめて置く場所。",
+ "detail": "階層構造で整理され、パスを使って場所を示す。GUI では一般にフォルダと呼ばれるものとほぼ同じ意味。",
+ "example": "src/components/"
+ },
+ {
+ "id": "root-directory",
+ "term": "root directory",
+ "match": ["ルートディレクトリ", "root folder", "ルートフォルダ"],
+ "short": "ディレクトリ階層のいちばん上にある場所。",
+ "detail": "ファイルシステム全体の起点を指す場合と、プロジェクトの最上位ディレクトリを指す場合がある。文脈によってどちらかを判断する。",
+ "example": "/"
+ },
+ {
+ "id": "current-directory",
+ "term": "current directory",
+ "match": ["カレントディレクトリ", "working directory", "作業ディレクトリ"],
+ "short": "プログラムやコマンドが現在の基準にしているディレクトリ。",
+ "detail": "相対パスはカレントディレクトリを起点に解釈される。ターミナルでは pwd、Node.js では process.cwd() で確認できる。",
+ "example": "process.cwd()"
+ },
+ {
+ "id": "javascript",
+ "term": "JavaScript",
+ "match": ["ジャバスクリプト", "JS"],
+ "short": "Web ページなどに動きや処理を加えるプログラミング言語。",
+ "detail": "ブラウザ上で画面の操作や通信を行えるほか、Node.js を使えばサーバやツールの開発にも使える。Java とは別の言語。",
+ "example": "const greeting = 'Hello'; console.log(greeting);",
+ "link": "https://developer.mozilla.org/ja/docs/Web/JavaScript"
+ },
+ {
+ "id": "typescript",
+ "term": "TypeScript",
+ "match": ["タイプスクリプト", "TS"],
+ "short": "JavaScript に型の仕組みを加えたプログラミング言語。",
+ "detail": "変数や関数が扱うデータの型を事前に検査できる。実行前に JavaScript へ変換されるため、ブラウザや Node.js で動かせる。",
+ "example": "const message: string = 'Hello';",
+ "link": "https://www.typescriptlang.org/docs/"
+ },
+ {
+ "id": "nodejs",
+ "term": "Node.js",
+ "match": ["Node", "NodeJS", "ノード", "ノードジェイエス"],
+ "short": "ブラウザの外で JavaScript を実行するための環境。",
+ "detail": "サーバ、コマンドラインツール、開発用ツールなどを JavaScript で作れる。npm を使って外部パッケージを導入できる。",
+ "example": "console.log(process.version);",
+ "link": "https://nodejs.org/ja"
+ },
+ {
+ "id": "vue",
+ "term": "Vue.js",
+ "match": ["Vue", "VueJS", "ビュー", "ビュージェイエス"],
+ "short": "Web の画面を部品に分けて作るための JavaScript フレームワーク。",
+ "detail": "データの変化に合わせて画面を自動で更新できる。HTML に近いテンプレートと、再利用できるコンポーネントを組み合わせて UI を作る。",
+ "example": "{{ message }}
",
+ "link": "https://ja.vuejs.org/"
+ },
+ {
+ "id": "nextjs",
+ "term": "Next.js",
+ "match": ["Next", "NextJS", "ネクスト", "ネクストジェイエス"],
+ "short": "React を使った Web アプリ開発のためのフレームワーク。",
+ "detail": "ルーティング、サーバでの描画、データ取得、ビルドなどの機能をまとめて提供する。React 単体よりもアプリ全体の構成を作りやすい。",
+ "example": "export default function Page() { return
Hello
", + "link": "https://developer.mozilla.org/ja/docs/Glossary/Tag", + "langs": ["html", "vue", "javascriptreact", "typescriptreact"] + }, + { + "id": "css-margin", + "term": "margin", + "match": ["マージン", "外側の余白"], + "short": "CSS で要素の境界線より外側に作る余白。", + "detail": "上下左右をまとめて指定したり、margin-top のように個別指定したりできる。隣り合う上下のマージンは相殺されることがある。", + "example": ".card { margin: 16px; }", + "link": "https://developer.mozilla.org/ja/docs/Web/CSS/margin", + "langs": ["css", "scss", "less"] + }, + { + "id": "css-border", + "term": "border", + "match": ["ボーダー", "境界線"], + "short": "CSS で要素の周囲に表示する境界線。", + "detail": "線の太さ、種類、色をまとめて指定できる。border-radius を加えると、境界線の角を丸くできる。", + "example": ".card { border: 1px solid #ccc; }", + "link": "https://developer.mozilla.org/ja/docs/Web/CSS/border", + "langs": ["css", "scss", "less"] + }, + { + "id": "css-padding", + "term": "padding", + "match": ["パディング", "内側の余白"], + "short": "CSS で要素の内容と境界線の間に作る余白。", + "detail": "上下左右をまとめて指定したり、padding-top のように個別指定したりできる。margin と違い、要素の背景は padding の領域にも表示される。", + "example": ".card { padding: 16px; }", + "link": "https://developer.mozilla.org/ja/docs/Web/CSS/padding", + "langs": ["css", "scss", "less"] + }, + { + "id": "css-height", + "term": "height", + "match": ["ハイト", "高さ"], + "short": "CSS で要素の高さを指定するプロパティ。", + "detail": "px、%、vh などの単位や auto を使って指定する。初期設定では内容領域の高さを表すが、box-sizing の設定によって計算方法が変わる。", + "example": ".hero { height: 100vh; }", + "link": "https://developer.mozilla.org/ja/docs/Web/CSS/height", + "langs": ["css", "scss", "less"] + }, + { + "id": "css-width", + "term": "width", + "match": ["ウィズ", "幅"], + "short": "CSS で要素の横幅を指定するプロパティ。", + "detail": "px、%、vw などの単位や auto を使って指定する。画面幅に合わせる場合は、max-width や min-width と組み合わせることも多い。", + "example": ".container { width: 100%; max-width: 960px; }", + "link": "https://developer.mozilla.org/ja/docs/Web/CSS/width", + "langs": ["css", "scss", "less"] + }, + { + "id": "box-model", + "term": "box model", + "match": ["ボックスモデル", "CSS box model"], + "short": "HTML 要素を四角い領域として扱う CSS の考え方。", + "detail": "内側から content、padding、border、margin の領域で構成される。要素全体の大きさを正しく計算するときに重要になる。", + "example": ".card { box-sizing: border-box; }", + "link": "https://developer.mozilla.org/ja/docs/Learn_web_development/Core/Styling_basics/Box_model", + "langs": ["css", "scss", "less"] + }, + { + "id": "responsive-web-design", + "term": "responsive web design", + "match": ["レスポンシブウェブデザイン", "responsive design", "レスポンシブデザイン", "RWD"], + "short": "画面の大きさに応じてレイアウトを調整する設計手法。", + "detail": "柔軟な幅、メディアクエリ、可変画像などを使い、スマートフォンから大きな画面まで見やすく操作しやすい表示を作る。", + "example": "@media (max-width: 600px) { .menu { display: none; } }", + "link": "https://developer.mozilla.org/ja/docs/Learn_web_development/Core/CSS_layout/Responsive_Design" + }, + { + "id": "npm", + "term": "npm", + "match": ["エヌピーエム"], + "short": "Node.js のパッケージを管理するためのツール。", + "detail": "外部ライブラリのインストール、バージョン管理、スクリプトの実行などに使う。プロジェクトの設定や依存関係は主に package.json に記録される。", + "example": "npm install", + "link": "https://docs.npmjs.com/about-npm" + }, + { + "id": "ubuntu", + "term": "Ubuntu", + "match": ["ウブンツ"], + "short": "使いやすさを重視して作られた Linux ディストリビューション。", + "detail": "デスクトップやサーバ、クラウド環境で利用される。ソフトウェアの導入や更新には apt というパッケージ管理ツールを使える。", + "example": "sudo apt update", + "link": "https://ubuntu.com/about" + }, + { + "id": "component", + "term": "component", + "match": ["コンポーネント", "UI component", "UIコンポーネント"], + "short": "画面を構成する再利用可能な部品。", + "detail": "ボタン、入力欄、ヘッダーなどを独立した単位として作り、組み合わせて画面を構築する。見た目や処理をまとめることで保守しやすくなる。", + "example": "" } - ] diff --git a/packages/core/src/dictionary.ts b/packages/core/src/dictionary.ts index 04fe99f..e7c3851 100644 --- a/packages/core/src/dictionary.ts +++ b/packages/core/src/dictionary.ts @@ -74,6 +74,27 @@ export class Dictionary { } return undefined; } + + findAll(text: string, options: LookupOptions = {}): Match[] { + const tokens = tokenize(text); + const matches: Match[] = []; + for (let start = 0; start < tokens.length; start++) { + for (let len = MAX_PHRASE_TOKENS; len >= 1; len--) { + if (start + len > tokens.length) continue; + const window = tokens.slice(start, start + len); + if (!isContiguous(text, window)) continue; + + const phrase = window.map((t) => t.text).join(' '); + const entry = this.lookup(phrase, options); + if (entry) { + matches.push({ entry, start: window[0].start, end: window[window.length - 1].end }); + start += len - 1; //forループでstartが++されることを考慮する + break; + } + } + } + return matches; + } } /** 窓内のトークンが空白・ハイフン程度でしか隔てられていないか。 */ diff --git a/packages/vscode/package.json b/packages/vscode/package.json index 1f58558..fcb1aa5 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -2,7 +2,7 @@ "name": "techword-vscode", "displayName": "TechWord", "description": "プログラミング用語にホバーすると、意味を簡潔に表示します。", - "version": "0.1.1", + "version": "0.2.1", "private": true, "publisher": "techword", "engines": {