テキストエディタ 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(); |