Skip to content

Instantly share code, notes, and snippets.

@unarist
Last active February 26, 2021 11:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unarist/a184bf5d936c82bed14007a56e8abfae to your computer and use it in GitHub Desktop.
Save unarist/a184bf5d936c82bed14007a56e8abfae to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name github - indent lines
// @namespace https://github.com/unarist/
// @version 0.1
// @description Tab/Shift+Tabでカーソル位置・選択行をインデント・アンインデント
// @author unarist
// @match https://github.com/*
// @grant none
// @downloadURL https://gist.github.com/unarist/a184bf5d936c82bed14007a56e8abfae/raw/github-indent-lines.user.js
// @run-at document-idle
// @noframes
// ==/UserScript==
/*
Tabが押されたらその行のインデントを深くする
Shift+Tabが押されたらインデントを浅くする
カーソル位置直前が /\* $/ /\* \[ \] $/ の場合に限定する?
keydownでpreventDefaultするとフォーカス移動は抑制できる
範囲選択してTab/Shift+TabはGithubが既に対応していた。が、execCommand使ってないのかUndo対応してない様子。
これを置き換えるために capture: 1 使ってしまった。。
*/
(function() {
'use strict';
const applyIndent = (el, unindent) => {
const linesStart = el.value.slice(0, el.selectionStart).lastIndexOf('\n') + 1;
const linesEnd = (() => {
const offset = el.value.slice(el.selectionEnd).indexOf('\n');
if (offset < 0) return el.value.length;
else return el.selectionEnd + offset;
})();
const prevLines = linesStart > 0 ? el.value.slice(0, linesStart - 1) : "";
const selectedLines = el.value.slice(linesStart, linesEnd);
const nextLines = el.value.slice(linesEnd + 1);
const modifiedSelectedLines = selectedLines.split('\n').map(x => unindent ? x.replace(/^ /, '') : ' ' + x).join('\n');
// unindentできないとずれるはず
const calcOffset = pos => pos <= linesStart ? 0 : selectedLines.slice(0, pos - linesStart).split('\n').length * (unindent ? -2 : 2);
const prevRange = [el.selectionStart, el.selectionEnd, el.selectionDirection];
// Undo可能にするために、value更新ではなくexecCommandを使っている
el.setSelectionRange(linesStart, linesEnd);
document.execCommand('insertText', false, modifiedSelectedLines);
el.setSelectionRange(prevRange[0] + calcOffset(prevRange[0]), prevRange[1] + calcOffset(prevRange[1]), prevRange[2]);
//el.value = [prevLines, modifiedSelectedLines, nextLines].join('\n');
};
window.addEventListener('keydown', e => {
if (e.code === 'Tab' && e.target.matches('textarea')) {
e.preventDefault();
e.stopPropagation();
applyIndent(e.target, e.shiftKey);
}
}, { capture: true });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment