GeezerVison is showing github.com — readline: make tab size configurable · nodejs/node@f9a27ea
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/readline.md +5Lines changed: 5 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -456,6 +456,9 @@ the current position of the cursor down. | 456 | 456 | <!-- YAML | 457 | 457 | added: v0.1.98 | 458 | 458 | changes: | | 459 | + - version: REPLACEME | | 460 | + pr-url: https://github.com/nodejs/node/pull/31318 | | 461 | + description: The `tabSize` option is supported now. | 459 | 462 | - version: v8.3.0, 6.11.4 | 460 | 463 | pr-url: https://github.com/nodejs/node/pull/13497 | 461 | 464 | description: Remove max limit of `crlfDelay` option. | @@ -499,6 +502,8 @@ changes: | 499 | 502 | can both form a complete key sequence using the input read so far and can | 500 | 503 | take additional input to complete a longer key sequence). | 501 | 504 | **Default:** `500`. | | 505 | + * `tabSize` {integer} The number of spaces a tab is equal to (minimum 1). | | 506 | + **Default:** `8`. | 502 | 507 |
| 503 | 508 | The `readline.createInterface()` method creates a new `readline.Interface` | 504 | 509 | instance. | |
Collapse file Copy file name to clipboardExpand all lines: lib/readline.js +12-4Lines changed: 12 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -45,7 +45,10 @@ const { | 45 | 45 | ERR_INVALID_CURSOR_POS, | 46 | 46 | ERR_INVALID_OPT_VALUE | 47 | 47 | } = require('internal/errors').codes; | 48 | | -const { validateString } = require('internal/validators'); | | 48 | +const { | | 49 | + validateString, | | 50 | + validateUint32, | | 51 | +} = require('internal/validators'); | 49 | 52 | const { | 50 | 53 | inspect, | 51 | 54 | getStringWidth, | @@ -105,6 +108,7 @@ function Interface(input, output, completer, terminal) { | 105 | 108 | this._sawKeyPress = false; | 106 | 109 | this._previousKey = null; | 107 | 110 | this.escapeCodeTimeout = ESCAPE_CODE_TIMEOUT; | | 111 | + this.tabSize = 8; | 108 | 112 |
| 109 | 113 | EventEmitter.call(this); | 110 | 114 | let historySize; | @@ -118,6 +122,11 @@ function Interface(input, output, completer, terminal) { | 118 | 122 | completer = input.completer; | 119 | 123 | terminal = input.terminal; | 120 | 124 | historySize = input.historySize; | | 125 | + if (input.tabSize !== undefined) { | | 126 | + const positive = true; | | 127 | + validateUint32(input.tabSize, 'tabSize', positive); | | 128 | + this.tabSize = input.tabSize; | | 129 | + } | 121 | 130 | removeHistoryDuplicates = input.removeHistoryDuplicates; | 122 | 131 | if (input.prompt !== undefined) { | 123 | 132 | prompt = input.prompt; | @@ -718,10 +727,9 @@ Interface.prototype._getDisplayPos = function(str) { | 718 | 727 | offset = 0; | 719 | 728 | continue; | 720 | 729 | } | 721 | | - // Tabs must be aligned by an offset of 8. | 722 | | - // TODO(BridgeAR): Make the tab size configurable. | | 730 | + // Tabs must be aligned by an offset of the tab size. | 723 | 731 | if (char === '\t') { | 724 | | - offset += 8 - (offset % 8); | | 732 | + offset += this.tabSize - (offset % this.tabSize); | 725 | 733 | continue; | 726 | 734 | } | 727 | 735 | const width = getStringWidth(char); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-readline-interface.js +52Lines changed: 52 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -138,6 +138,39 @@ function assertCursorRowsAndCols(rli, rows, cols) { | 138 | 138 | name: 'RangeError', | 139 | 139 | code: 'ERR_INVALID_OPT_VALUE' | 140 | 140 | }); | | 141 | + | | 142 | + // Check for invalid tab sizes. | | 143 | + assert.throws( | | 144 | + () => new readline.Interface({ | | 145 | + input, | | 146 | + tabSize: 0 | | 147 | + }), | | 148 | + { | | 149 | + message: 'The value of "tabSize" is out of range. ' + | | 150 | + 'It must be >= 1 && < 4294967296. Received 0', | | 151 | + code: 'ERR_OUT_OF_RANGE' | | 152 | + } | | 153 | + ); | | 154 | + | | 155 | + assert.throws( | | 156 | + () => new readline.Interface({ | | 157 | + input, | | 158 | + tabSize: '4' | | 159 | + }), | | 160 | + { code: 'ERR_INVALID_ARG_TYPE' } | | 161 | + ); | | 162 | + | | 163 | + assert.throws( | | 164 | + () => new readline.Interface({ | | 165 | + input, | | 166 | + tabSize: 4.5 | | 167 | + }), | | 168 | + { | | 169 | + code: 'ERR_OUT_OF_RANGE', | | 170 | + message: 'The value of "tabSize" is out of range. ' + | | 171 | + 'It must be an integer. Received 4.5' | | 172 | + } | | 173 | + ); | 141 | 174 | } | 142 | 175 |
| 143 | 176 | // Sending a single character with no newline | @@ -632,6 +665,25 @@ function assertCursorRowsAndCols(rli, rows, cols) { | 632 | 665 | rli.close(); | 633 | 666 | } | 634 | 667 |
| | 668 | +// Multi-line input cursor position and long tabs | | 669 | +{ | | 670 | + const [rli, fi] = getInterface({ tabSize: 16, terminal: true, prompt: '' }); | | 671 | + fi.columns = 10; | | 672 | + fi.emit('data', 'multi-line\ttext \t'); | | 673 | + assert.strictEqual(rli.cursor, 17); | | 674 | + assertCursorRowsAndCols(rli, 3, 2); | | 675 | + rli.close(); | | 676 | +} | | 677 | + | | 678 | +// Check for the default tab size. | | 679 | +{ | | 680 | + const [rli, fi] = getInterface({ terminal: true, prompt: '' }); | | 681 | + fi.emit('data', 'the quick\tbrown\tfox'); | | 682 | + assert.strictEqual(rli.cursor, 19); | | 683 | + // The first tab is 7 spaces long, the second one 3 spaces. | | 684 | + assertCursorRowsAndCols(rli, 0, 27); | | 685 | +} | | 686 | + | 635 | 687 | // Multi-line prompt cursor position | 636 | 688 | { | 637 | 689 | const [rli, fi] = getInterface({ | |
|