テキストエディタ Mery 用の自作マクロ集。
随時更新予定。
// ------------------------------------------------------------ | |
// インデント直後では逆インデント、それ以外は直前の1字を削除 | |
// ------------------------------------------------------------ | |
function selectLine() { | |
document.selection.EndOfLine(false, mePosLogical); | |
document.selection.StartOfLine(true, mePosLogical); | |
} | |
function getIndentDepth(s) { | |
const indentChar = new RegExp("^[ \t]+"); | |
const m = indentChar.exec(s); | |
if (m) { | |
return m[0].length; | |
} | |
return 0; | |
} | |
function outdent() { | |
const slct = document.selection; | |
if (!slct.IsEmpty || slct.Mode != meModeStream) { | |
slct.DeleteLeft(1); | |
return; | |
} | |
const cursorX = slct.GetActivePointX(mePosLogical); | |
const cursorY = slct.GetActivePointY(mePosLogical); | |
const line = document.GetLine(cursorY, 1); | |
const depth = getIndentDepth(line); | |
if (!depth || depth != cursorX - 1) { | |
slct.DeleteLeft(1); | |
return; | |
} | |
selectLine(); | |
slct.UnIndent(); | |
const outdented = document.GetLine(cursorY, 1); | |
const postDepth = getIndentDepth(outdented); | |
const postX = (postDepth)? 1+postDepth : 1; | |
document.selection.SetActivePoint(mePosLogical, postX, cursorY); | |
} | |
function main() { | |
Redraw = false; | |
outdent(); | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 次の段落までジャンプ | |
// ------------------------------------------------------------ | |
const wholeLines = document.text.split(/\r?\n/); | |
const max = wholeLines.length; | |
const blank = new RegExp("^ *$"); | |
function isBlankLine(logicalY) { | |
const logicalLine = wholeLines[logicalY-1]; | |
return blank.test(logicalLine); | |
} | |
function cursorDown(n) { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, 1, y+n, false); | |
} | |
function toParagraphEnd() { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
let down = max - y; | |
for (let i = 1; i <= max-y; i++) { | |
if (isBlankLine(y+i)) { | |
down = i - 1; | |
break; | |
} | |
} | |
cursorDown(down); | |
document.selection.EndOfLine(false, mePosLogical); | |
} | |
function skipBlankAreaDown() { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
let down = max - y; | |
for (let i = 1; i <= max-y; i++) { | |
if (!isBlankLine(y+i)) { | |
down = i; | |
break; | |
} | |
} | |
cursorDown(down); | |
} | |
function main() { | |
if (document.selection.Mode != meModeStream) { | |
return; | |
} | |
const x = document.selection.GetActivePointX(mePosLogical); | |
const y = document.selection.GetActivePointY(mePosLogical); | |
const line = wholeLines[y-1]; | |
if (y == max) { | |
document.selection.EndOfLine(false, mePosLogical) | |
return; | |
} | |
if (isBlankLine(y)) { | |
skipBlankAreaDown(); | |
return; | |
} | |
if (isBlankLine(y+1) && x == line.length+1) { | |
skipBlankAreaDown(); | |
return; | |
} | |
toParagraphEnd(); | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 前の段落までジャンプ | |
// ------------------------------------------------------------ | |
const wholeLines = document.text.split(/\r?\n/); | |
const blank = new RegExp("^ *$"); | |
function isBlankLine(logicalY) { | |
const logicalLine = wholeLines[logicalY-1]; | |
return blank.test(logicalLine); | |
} | |
function cursorUp(n) { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, 1, y-n, false); | |
} | |
function toParagraphBeginning() { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
let up = y - 1; | |
for (let i = 1; i < y; i++) { | |
if (isBlankLine(y-i)) { | |
up = i - 1; | |
break; | |
} | |
} | |
cursorUp(up); | |
} | |
function skipBlankAreaUp() { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
let up = y - 1; | |
for (let i = 1; i < y; i++) { | |
if (!isBlankLine(y-i)) { | |
up = i; | |
break; | |
} | |
} | |
cursorUp(up); | |
document.selection.EndOfLine(false, mePosLogical); | |
} | |
function main() { | |
if (document.selection.Mode != meModeStream) { | |
return | |
} | |
const x = document.selection.GetActivePointX(mePosLogical); | |
const y = document.selection.GetActivePointY(mePosLogical); | |
if (y == 1) { | |
document.selection.StartOfLine(false, mePosLogical); | |
return; | |
} | |
if (isBlankLine(y)) { | |
skipBlankAreaUp(); | |
return; | |
} | |
if (isBlankLine(y-1) && x == 1) { | |
skipBlankAreaUp(); | |
return; | |
} | |
toParagraphBeginning(); | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 直後の句読点の後ろに移動する | |
// ------------------------------------------------------------ | |
const wholeLines = document.text.split(/\r?\n/); | |
const max = wholeLines.length; | |
const zen = "[、,。;:「」『』【】()〔〕《》〈〉[]・!?←↓↑→○●▲△▼▽◆◇■□★☆~/…― ]"; | |
const han = "[\\[\\]\\(\\)\\.,=<>:;`'\" #]"; | |
const punc = new RegExp(zen+"|"+han); | |
function getLogicalLine(y) { | |
return wholeLines[y-1]; | |
} | |
function hasPunctuation(logicalY) { | |
const logicalLine = wholeLines[logicalY-1]; | |
return punc.test(logicalLine); | |
} | |
function jumpToLine(startY) { | |
let down = 0; | |
for (let i = 1; i <= max-startY; i++) { | |
if (hasPunctuation(startY+i)) { | |
down = i; | |
break; | |
} | |
} | |
document.selection.SetActivePoint(mePosLogical, 1, startY+down, false); | |
} | |
function setCursorPos(xLogical, yLogical, expandSelection) { | |
document.selection.SetActivePoint(mePosLogical, xLogical, yLogical, expandSelection); | |
} | |
function moveCursor() { | |
let cursorX = document.selection.GetActivePointX(mePosLogical); | |
let cursorY = document.selection.GetActivePointY(mePosLogical); | |
if (cursorX == getLogicalLine(cursorY).length + 1) { | |
if (cursorY == max) { | |
return; | |
} | |
jumpToLine(cursorY); | |
cursorX = 1; | |
cursorY = document.selection.GetActivePointY(mePosLogical); | |
} | |
document.selection.EndOfLine(true, mePosLogical); | |
const strToEndOfLine = document.selection.Text; | |
const reg = new RegExp("(^.*?(" + zen + "|" + han + ")+)(.*$)"); | |
const m = reg.exec(strToEndOfLine); | |
if (!m) { | |
document.selection.EndOfLine(false, mePosLogical); | |
return; | |
} | |
const firstMatch = String(m[1]); | |
setCursorPos(cursorX+firstMatch.length, cursorY, false); | |
} | |
function main() { | |
if (!document.selection.IsEmpty || document.selection.Mode != meModeStream) { | |
return | |
} | |
Redraw = false; | |
moveCursor(); | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 直前の句読点の前に移動する | |
// ------------------------------------------------------------ | |
const wholeLines = document.text.split(/\r?\n/); | |
const max = wholeLines.length; | |
const zen = "[、,。;:「」『』【】()〔〕《》〈〉[]・!?←↓↑→○●▲△▼▽◆◇■□★☆~/…― ]"; | |
const han = "[\\[\\]\\(\\)\\.,=<>:;`'\" #]"; | |
const punc = new RegExp(zen+"|"+han); | |
function getLogicalLine(y) { | |
return wholeLines[y-1]; | |
} | |
function hasPunctuation(logicalY) { | |
const logicalLine = wholeLines[logicalY-1]; | |
return punc.test(logicalLine); | |
} | |
function jumpToLine(startY) { | |
let up = 0; | |
for (let i = 1; i < startY; i++) { | |
if (hasPunctuation(startY-i)) { | |
up = i; | |
break; | |
} | |
} | |
const x = getLogicalLine(startY-up).length + 1; | |
document.selection.SetActivePoint(mePosLogical, x, startY-up, false); | |
} | |
function setCursorPos(xLogical, yLogical, expandSelection) { | |
document.selection.SetActivePoint(mePosLogical, xLogical, yLogical, expandSelection); | |
} | |
function moveCursor() { | |
let cursorX = document.selection.GetActivePointX(mePosLogical); | |
let cursorY = document.selection.GetActivePointY(mePosLogical); | |
if (cursorX == 1) { | |
if (cursorY == 1) { | |
return; | |
} | |
jumpToLine(cursorY); | |
cursorY = document.selection.GetActivePointY(mePosLogical); | |
cursorX = document.selection.GetActivePointX(mePosLogical); | |
} | |
document.selection.StartOfLine(true, mePosLogical); | |
const strToStartOfLine = document.selection.Text; | |
const zen = "[、,。;:「」『』【】()〔〕〈〉《》・!?←↓↑→○●▲△▼▽◆◇■□★☆~/…― ]"; | |
const han = "[\\[\\]\\(\\)\\.,=<>:;`'\" #]"; | |
const reg = new RegExp("(^.*(" + zen + "|" + han + "))(.*?$)"); | |
const m = reg.exec(strToStartOfLine); | |
if (!m) { | |
document.selection.StartOfLine(false, mePosLogical); | |
return; | |
} | |
const firstMatch = String(m[1]); | |
const trailing = new RegExp("(" + zen + "|" + han + ")+$"); | |
const net = firstMatch.replace(trailing, ""); | |
const delta = (strToStartOfLine.length - net.length > 0)? strToStartOfLine.length - net.length : 1; | |
setCursorPos(cursorX-delta, cursorY, false); | |
} | |
function main() { | |
if (!document.selection.IsEmpty || document.selection.Mode != meModeStream) { | |
return | |
} | |
Redraw = false; | |
moveCursor(); | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 行頭に移動する | |
// ・折り返し状態での表示行頭で実行すると論理行頭に移動。 | |
// ・インデント無しの行頭で実行すると段落先頭に移動。 | |
// ------------------------------------------------------------ | |
const selecting = false; | |
function getIndentDepth(s) { | |
const indentChar = new RegExp("^[ \t]+"); | |
const m = indentChar.exec(s); | |
if (m) { | |
return m[0].length; | |
} | |
return 0; | |
} | |
function toBOL () { | |
const logicalX = document.selection.GetActivePointX(mePosLogical); | |
const logicalY = document.selection.GetActivePointY(mePosLogical); | |
const viewX = document.selection.GetActivePointX(mePosView); | |
const viewY = document.selection.GetActivePointY(mePosView); | |
const logicalLine = document.GetLine(logicalY, 1); | |
const indentDepth = getIndentDepth(logicalLine); | |
if (viewY == 1) { | |
document.Selection.StartOfLine(selecting, mePosView); | |
return; | |
} | |
document.Selection.StartOfLine(selecting, mePosView); | |
if (logicalX == indentDepth+1) { | |
return; | |
} | |
document.Selection.CharLeft(selecting, 1); | |
const inSecondLine = document.Selection.GetActivePointY(mePosLogical) == logicalY; | |
document.Selection.CharRight(selecting, 2); | |
document.Selection.CharLeft(selecting, 1); | |
if (inSecondLine) { | |
if (viewX > 1) { | |
return; | |
} | |
document.Selection.StartOfLine(selecting, mePosLogical); | |
} | |
if (indentDepth < 1) { | |
return; | |
} | |
document.Selection.SetActivePoint(mePosLogical, indentDepth+1, logicalY, selecting); | |
} | |
function main() { | |
if (document.Selection.Mode != meModeStream) { | |
document.Selection.StartOfLine(selecting, mePosView); | |
return; | |
} | |
Redraw = false; | |
toBOL(); | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 行末に移動する | |
// 折り返し末尾で実行すると論理行末に移動。 | |
// ------------------------------------------------------------ | |
function main () { | |
const viewY = document.selection.GetActivePointY(mePosView); | |
const viewX = document.selection.GetActivePointX(mePosView); | |
const viewLine = document.getLine(viewY); | |
const selected = !document.selection.IsEmpty; | |
const opt = (viewX == viewLine.length+1)? mePosLogical : mePosView; | |
document.selection.EndOfLine(selected, opt); | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 現在のカーソル位置を上に持ってくる | |
// ------------------------------------------------------------ | |
function main () { | |
var currentLine = Document.Selection.GetActivePointY(mePosView); | |
ScrollY = currentLine - 2; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// カッコ内を選択 | |
// ------------------------------------------------------------ | |
function getNthChar(s, n) { | |
return String(s.charAt(n-1)); | |
} | |
const bracePairs = { | |
"(": ")", | |
"「": "」", | |
"[": "]", | |
"〔": "〕", | |
"『": "』", | |
"【": "】", | |
"〈": "〉", | |
"《": "》", | |
} | |
const openBraces = Object.keys(bracePairs).map(function(key){ | |
return String(key); | |
}); | |
const closeBraces = Object.keys(bracePairs).map(function(key){ | |
const closeBrc = bracePairs[key]; | |
return String(closeBrc); | |
}); | |
function getOpenBrace(closeBrc) { | |
const openBrc = Object.keys(bracePairs).filter(function(key){ | |
return bracePairs[key] === closeBrc | |
}); | |
return String(openBrc); | |
} | |
function getOpenBraceX (line) { | |
let x = 0; | |
const len = line.length; | |
const stack = []; | |
for (let i = 0; i < len; i++) { | |
const c = getNthChar(line, len - i); | |
if (closeBraces.indexOf(c) >= 0) { | |
stack.push(getOpenBrace(c)); | |
continue; | |
} | |
if (openBraces.indexOf(c) >= 0) { | |
let idx = stack.indexOf(c); | |
if (idx >= 0) { | |
stack.splice(idx, 1); | |
continue; | |
} | |
x = len - i; | |
break; | |
} | |
} | |
return x; | |
} | |
function getCloseBraceX (line, closeBrace) { | |
let x = 0; | |
const openBrace = getOpenBrace(closeBrace); | |
let skipCloseBrace = 0; | |
for (let i = 1; i <= line.length; i++) { | |
const c = getNthChar(line, i); | |
if (c == openBrace) { | |
skipCloseBrace += 1; | |
continue; | |
} | |
if (c == closeBrace) { | |
if (skipCloseBrace) { | |
skipCloseBrace -= 1; | |
continue; | |
} | |
x = i; | |
break; | |
} | |
} | |
return x; | |
} | |
function expandSelection() { | |
const logicalX = document.selection.GetActivePointX(mePosLogical); | |
const logicalY = document.selection.GetActivePointY(mePosLogical); | |
const logicalLine = document.GetLine(logicalY, 1); | |
const strFromBOL = logicalLine.slice(0, logicalX-1); | |
const openPosX = getOpenBraceX(strFromBOL); | |
if (openPosX < 1) { | |
return; | |
} | |
const openBrc = getNthChar(logicalLine, openPosX); | |
const closeBrc = bracePairs[openBrc]; | |
const strToEOL = logicalLine.slice(openPosX); | |
const closePosX = getCloseBraceX(strToEOL, closeBrc); | |
if (closePosX < 1) { | |
return; | |
} | |
document.selection.SetActivePoint(mePosLogical, openPosX+1, logicalY, false); | |
document.selection.SetActivePoint(mePosLogical, openPosX+closePosX, logicalY, true); | |
} | |
function main() { | |
if (document.selection.Mode != meModeStream) { | |
return | |
} | |
Redraw = false; | |
expandSelection(); | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 段落選択 | |
// ------------------------------------------------------------ | |
const wholeLines = document.text.split(/\r?\n/); | |
const max = wholeLines.length; | |
const blank = new RegExp("^ *$"); | |
function isBlankLine(logicalY) { | |
const logicalLine = wholeLines[logicalY-1]; | |
return blank.test(logicalLine); | |
} | |
function cursorUp(n) { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, 1, y-n, false); | |
} | |
function selectDown(n) { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, 1, y+n, true); | |
} | |
function moveToParagraphBeginning() { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
let up = 0; | |
for (let i = 1; i < y; i++) { | |
if (isBlankLine(y-i)) { | |
break; | |
} | |
up++ | |
} | |
cursorUp(up); | |
} | |
function selectParagraphToEnd() { | |
const y = document.selection.GetActivePointY(mePosLogical); | |
let down = 0; | |
for (let i = 1; i <= max-y; i++) { | |
if (isBlankLine(y+i)) { | |
break; | |
} | |
down++ | |
} | |
selectDown(down); | |
document.selection.EndOfLine(true, mePosLogical); | |
} | |
function main() { | |
if (document.selection.Mode != meModeStream) { | |
return; | |
} | |
const y = document.selection.GetActivePointY(mePosLogical); | |
if (isBlankLine(y)) { | |
return; | |
} | |
if(document.selection.IsEmpty){ | |
moveToParagraphBeginning(); | |
} | |
selectParagraphToEnd(); | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 行頭に移動する | |
// ・折り返し状態での表示行頭で実行すると論理行頭に移動。 | |
// ・インデント無しの行頭で実行すると段落先頭に移動。 | |
// ------------------------------------------------------------ | |
const selecting = true; | |
function getIndentDepth(s) { | |
const indentChar = new RegExp("^[ \t]+"); | |
const m = indentChar.exec(s); | |
if (m) { | |
return m[0].length; | |
} | |
return 0; | |
} | |
function toBOL () { | |
const logicalX = document.selection.GetActivePointX(mePosLogical); | |
const logicalY = document.selection.GetActivePointY(mePosLogical); | |
const viewX = document.selection.GetActivePointX(mePosView); | |
const viewY = document.selection.GetActivePointY(mePosView); | |
const logicalLine = document.GetLine(logicalY, 1); | |
const indentDepth = getIndentDepth(logicalLine); | |
if (viewY == 1) { | |
document.Selection.StartOfLine(selecting, mePosView); | |
return; | |
} | |
document.Selection.StartOfLine(selecting, mePosView); | |
if (logicalX == indentDepth+1) { | |
return; | |
} | |
document.Selection.CharLeft(selecting, 1); | |
const inSecondLine = document.Selection.GetActivePointY(mePosLogical) == logicalY; | |
document.Selection.CharRight(selecting, 2); | |
document.Selection.CharLeft(selecting, 1); | |
if (inSecondLine) { | |
if (viewX > 1) { | |
return; | |
} | |
document.Selection.StartOfLine(selecting, mePosLogical); | |
} | |
if (indentDepth < 1) { | |
return; | |
} | |
document.Selection.SetActivePoint(mePosLogical, indentDepth+1, logicalY, selecting); | |
} | |
function main() { | |
if (document.Selection.Mode != meModeStream) { | |
document.Selection.StartOfLine(selecting, mePosView); | |
return; | |
} | |
Redraw = false; | |
toBOL(); | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 現在位置からファイル末尾まで選択(スクロール位置保存) | |
// ------------------------------------------------------------ | |
function main() { | |
const sX = ScrollX | |
const sY = ScrollY; | |
const curPos = document.Selection.GetActivePos(); | |
Redraw = false; | |
document.selection.EndOfDocument(); | |
document.selection.SetActivePos(curPos, true); | |
ScrollX = sX; | |
ScrollY = sY; | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// 行末に移動する | |
// 折り返し末尾で実行すると論理行末に移動。 | |
// ------------------------------------------------------------ | |
const selecting = true; | |
function main () { | |
const viewY = document.selection.GetActivePointY(mePosView); | |
const viewX = document.selection.GetActivePointX(mePosView); | |
const viewLine = document.getLine(viewY); | |
const opt = (viewX == viewLine.length+1)? mePosLogical : mePosView; | |
document.selection.EndOfLine(selecting, opt); | |
} | |
main(); |
// ------------------------------------------------------------ | |
// カーソルを下に動かす | |
// 選択中であれば常に選択範囲の下端に。 | |
// ------------------------------------------------------------ | |
function main () { | |
if (document.selection.IsEmpty || document.selection.Mode != meModeStream) { | |
document.selection.LineDown(); | |
return; | |
} | |
Redraw = false; | |
const x = document.selection.GetBottomPointX(mePosLogical); | |
const y = document.selection.GetBottomPointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, x, y) | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// カーソルを左に動かす | |
// 選択中であれば常に選択範囲の左に。 | |
// ------------------------------------------------------------ | |
function main () { | |
if (document.selection.IsEmpty) { | |
document.selection.CharLeft(); | |
return; | |
} | |
if (document.selection.Mode != meModeStream) { | |
document.selection.Collapse(meCollapseStart); | |
return; | |
} | |
Redraw = false; | |
const x = document.selection.GetTopPointX(mePosLogical); | |
const y = document.selection.GetTopPointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, x, y) | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// カーソルを右に動かす | |
// 選択中であれば常に選択範囲の右に。 | |
// ------------------------------------------------------------ | |
function main () { | |
if (document.selection.IsEmpty) { | |
document.selection.CharRight(); | |
return; | |
} | |
if (document.selection.Mode != meModeStream) { | |
document.selection.Collapse(meCollapseEnd); | |
return; | |
} | |
Redraw = false; | |
const x = document.selection.GetBottomPointX(mePosLogical); | |
const y = document.selection.GetBottomPointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, x, y) | |
Redraw = true; | |
} | |
main(); |
// ------------------------------------------------------------ | |
// カーソルを上に動かす | |
// 選択中であれば常に選択範囲の上端に。 | |
// ------------------------------------------------------------ | |
function main () { | |
if (document.selection.IsEmpty || document.selection.Mode != meModeStream) { | |
document.selection.LineUp(); | |
return; | |
} | |
Redraw = false; | |
const x = document.selection.GetTopPointX(mePosLogical); | |
const y = document.selection.GetTopPointY(mePosLogical); | |
document.selection.SetActivePoint(mePosLogical, x, y) | |
Redraw = true; | |
} | |
main(); |