generated at
カーソル行から特定の文字列を抽出するテスト
カーソルがある行から、外部リンクに相当する文字列を抽出して表示するテスト

仕様
[/ ] で囲まれた部分を括弧付きで表示する
表示部分のscriptはカーソル行をUserScriptで取得するテストのscript.jsを使う
抽出する文字列の性質
最初 [/ で始まる
最後が ] で終わる
カーソルを含むもののみ抽出
抽出方法
正規表現だけだと無理そう
カーソルと比べて、どの位置にあるのかがわからない
こういうalgorithmだとどうだ?
1. 前から順番に [ / と並んでいるspanを探す
2. 探したら、 / * 次の文字offsetLeftを取得する
この値とcursorのleftとが一致する
3. カーソルのleftに一番近いものを探す
この時点でどれもカーソルのleftより大きかったら補完しない
先に正規表現で大雑把に探したほうが良さそう
/\[\/[^\s!"#%&'()\*\+,\-\.\/\{\|\}<>_~]+[^\]]*\]/ で探せる?
探したら、その文字列に一致する文字列の先頭文字のclassを取得する
正規表現がマッチした位置を取得できれば、そこからclass名を逆算できる
あとは、カーソルのleftと比較し、判定が通れば補完を開始する
条件
/ の次の文字のoffsetLeft <= cursorのleft
[ の内側でいいや。
] offsetLeft
>= cursorのleft
行のテキストは、spanのtextContentからとりだす
インデントも入れる(正規表現を使うのでどうせ引っかからない)
textContentを使うとインデントを1文字として出力してくれる
必要な関数
正規表現がマッチした文字の先頭からの位置を取得する関数
インデント込みの先頭からの文字の位置から文字のoffsetLeftを取得する関数
対象行の c-x の番号
インデント込みの文字の位置を取得できるので、この位置を c-x にそのまま当てはめられる

script.js
class suggestWindow{ constructor() { this.box = document.createElement('div'); this.box.classList.add('form-group'); this.box.style.position = 'absolute'; this.container = document.createElement('div'); this.container.classList.add('dropdown'); this.box.appendChild(this.container); this.items = document.createElement('ul'); this.items.classList.add('dropdown-menu'); this.items.style.whiteSpace='nowrap'; // 文字列を折り返さない this.container.appendChild(this.items); this.editor = document.getElementById('editor'); this.editor.appendChild(this.box); } // 入力補完window を開く open() { this.container.classList.add('open'); } close() { this.container.classList.remove('open'); } // 入力候補に表示するアイテムを更新する updateItems(items) { const newList = document.createElement('ul'); newList.classList.add('dropdown-menu'); newList.style.whiteSpace='nowrap'; for(const item of items) { let listItem = document.createElement('li'); listItem.classList.add('dropdown-item'); listItem.innerHTML = item; newList.appendChild(listItem) } this.items.replaceWith(newList); this.items = newList; // これを書かないと置き換えが完了しない } } const suggestion=new suggestWindow(); suggestion.editor.addEventListener('keyup',() => { let text= 'No line is focused.' if(suggestion.editor.getElementsByClassName('cursor-line').length!=0){ let line = suggestion.editor.getElementsByClassName('cursor-line')[0]; text = line.textContent; } //if(!/\[\//.test(text)) { // suggestion.close(); // return; //} suggestion.open(); let list = [text, ...[...text.matchAll(/\[\/[^\s!"#%&'()\*\+,\-\.\/\{\|\}<>_~\]]+[^\]]*\]/g)] .map(match => `Found ${match[0]} start=${match.index} end=${match.index + match[0].length -1}.`)];
done正規表現テスト
これも/shokaiマッチするはず
これはUserScriptマッチしない
複数あってもマッチする/shokaisss/shokai
ちゃんと別々にマッチする
斜体はマッチしない
斜体+文字装飾記法マッチしないよー/takker

script.js
suggestion.updateItems(list); const cursor = document.getElementById('text-input'); // 入力補完windowの位置を更新する suggestion.box.style.top = `${parseInt(cursor.style.top) + parseInt(cursor.style.height) + 3}px`; suggestion.box.style.left = `${parseInt(cursor.style.left)}px`; });