|
259 | 259 | } |
260 | 260 |
|
261 | 261 | if (e.key === 'Tab' && e.target === this.editor) { |
262 | | - e.preventDefault(); |
263 | | - document.execCommand('insertText', false, '\t'); |
| 262 | + this.handleSmartTab(e); |
264 | 263 | return; |
265 | 264 | } |
266 | 265 |
|
|
616 | 615 | } |
617 | 616 | } |
618 | 617 |
|
| 618 | + handleSmartTab(e) { |
| 619 | + const { value, selectionStart } = this.editor; |
| 620 | + const lineStart = value.lastIndexOf('\n', selectionStart - 1) + 1; |
| 621 | + const lineEnd = value.indexOf('\n', selectionStart); |
| 622 | + const line = value.substring(lineStart, lineEnd === -1 ? value.length : lineEnd); |
| 623 | + |
| 624 | + const isList = line.match(/^(\s*)([-*]|\d+\.)\s/); |
| 625 | + |
| 626 | + e.preventDefault(); |
| 627 | + if (isList && e.shiftKey) { |
| 628 | + const outdented = line.replace(/^\t/, ''); |
| 629 | + if (outdented === line) return; |
| 630 | + this.editor.setSelectionRange(lineStart, lineStart + line.length); |
| 631 | + document.execCommand('insertText', false, outdented); |
| 632 | + this.editor.setSelectionRange(selectionStart - 1, selectionStart - 1); |
| 633 | + } else if (isList && !e.shiftKey) { |
| 634 | + this.editor.setSelectionRange(lineStart, lineStart); |
| 635 | + document.execCommand('insertText', false, '\t'); |
| 636 | + this.editor.setSelectionRange(selectionStart + 1, selectionStart + 1); |
| 637 | + } else if (!e.shiftKey) { |
| 638 | + // Plain text: insert tab |
| 639 | + document.execCommand('insertText', false, '\t'); |
| 640 | + } |
| 641 | + // Shift+Tab on plain text: no-op (but still preventDefault to avoid focus jump) |
| 642 | + } |
| 643 | + |
619 | 644 | about() { |
620 | 645 | window.open('https://github.com/vsakkas/shiro', '_blank'); |
621 | 646 | } |
|
0 commit comments