├── fixtures ├── unicode_expected │ ├── keepOnlyDuplicateLines │ ├── sortLines │ ├── sortLinesNatural │ ├── sortLinesReverse │ ├── sortLinesShuffle │ ├── sortLinesUnique │ ├── removeDuplicateLines │ ├── sortLinesLineLength │ ├── sortLinesVariableLength │ ├── keepOnlyNotDuplicateLines │ ├── sortLinesCaseInsensitive │ ├── sortLinesLineLengthReverse │ ├── sortLinesCaseInsensitiveUnique │ └── sortLinesVariableLengthReverse ├── line_length_expected │ ├── keepOnlyDuplicateLines │ ├── sortLines │ ├── sortLinesNatural │ ├── sortLinesReverse │ ├── sortLinesShuffle │ ├── sortLinesUnique │ ├── removeDuplicateLines │ ├── sortLinesLineLength │ ├── keepOnlyNotDuplicateLines │ ├── sortLinesCaseInsensitive │ ├── sortLinesLineLengthReverse │ ├── sortLinesVariableLength │ ├── sortLinesCaseInsensitiveUnique │ └── sortLinesVariableLengthReverse ├── unicode_fixture ├── shuffled_lowercase_expected │ ├── keepOnlyDuplicateLines │ ├── keepOnlyNotDuplicateLines │ ├── sortLines │ ├── sortLinesUnique │ ├── removeDuplicateLines │ ├── sortLinesNatural │ ├── sortLinesReverse │ ├── sortLinesShuffle │ ├── sortLinesLineLength │ ├── sortLinesCaseInsensitive │ ├── sortLinesCaseInsensitiveUnique │ ├── sortLinesLineLengthReverse │ ├── sortLinesVariableLength │ └── sortLinesVariableLengthReverse ├── variables_expected │ ├── keepOnlyDuplicateLines │ ├── keepOnlyNotDuplicateLines │ ├── sortLinesUnique │ ├── removeDuplicateLines │ ├── sortLinesCaseInsensitiveUnique │ ├── sortLines │ ├── sortLinesNatural │ ├── sortLinesReverse │ ├── sortLinesShuffle │ ├── sortLinesLineLength │ ├── sortLinesCaseInsensitive │ ├── sortLinesLineLengthReverse │ ├── sortLinesVariableLength │ └── sortLinesVariableLengthReverse ├── shuffled_lowercase_fixture ├── variables_fixture └── line_length_fixture ├── .gitignore ├── images ├── icon.png ├── usage-animation.gif └── install-animation.gif ├── .vscodeignore ├── eslint.config.mjs ├── .editorconfig ├── tsconfig.json ├── .vscode ├── tasks.json └── launch.json ├── src ├── test │ ├── runTest.ts │ └── suite │ │ ├── index.ts │ │ └── sort-lines.test.ts ├── extension.ts └── sort-lines.ts ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── LICENSE ├── webpack.config.js ├── README.md ├── CHANGELOG.md └── package.json /fixtures/unicode_expected/keepOnlyDuplicateLines: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fixtures/line_length_expected/keepOnlyDuplicateLines: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fixtures/unicode_fixture: -------------------------------------------------------------------------------- 1 | 012345 2 | 0123456789 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/keepOnlyDuplicateLines: -------------------------------------------------------------------------------- 1 | dd -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLines: -------------------------------------------------------------------------------- 1 | 012345 2 | 0123456789 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/variables_expected/keepOnlyDuplicateLines: -------------------------------------------------------------------------------- 1 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesNatural: -------------------------------------------------------------------------------- 1 | 𝟘𝟙𝟚𝟛 2 | 012345 3 | 0123456789 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesReverse: -------------------------------------------------------------------------------- 1 | 𝟘𝟙𝟚𝟛 2 | 0123456789 3 | 012345 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesShuffle: -------------------------------------------------------------------------------- 1 | 012345 2 | 0123456789 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesUnique: -------------------------------------------------------------------------------- 1 | 012345 2 | 0123456789 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/unicode_expected/removeDuplicateLines: -------------------------------------------------------------------------------- 1 | 012345 2 | 0123456789 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesLineLength: -------------------------------------------------------------------------------- 1 | 𝟘𝟙𝟚𝟛 2 | 012345 3 | 0123456789 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesVariableLength: -------------------------------------------------------------------------------- 1 | 𝟘𝟙𝟚𝟛 2 | 012345 3 | 0123456789 -------------------------------------------------------------------------------- /fixtures/unicode_expected/keepOnlyNotDuplicateLines: -------------------------------------------------------------------------------- 1 | 012345 2 | 0123456789 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesCaseInsensitive: -------------------------------------------------------------------------------- 1 | 𝟘𝟙𝟚𝟛 2 | 012345 3 | 0123456789 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesLineLengthReverse: -------------------------------------------------------------------------------- 1 | 0123456789 2 | 012345 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | out/ 4 | .vscode-test/ 5 | *.vsix 6 | yarn.lock 7 | -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_fixture: -------------------------------------------------------------------------------- 1 | cc 2 | d 3 | aa 4 | c 5 | b 6 | bb 7 | a 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesCaseInsensitiveUnique: -------------------------------------------------------------------------------- 1 | 𝟘𝟙𝟚𝟛 2 | 012345 3 | 0123456789 -------------------------------------------------------------------------------- /fixtures/unicode_expected/sortLinesVariableLengthReverse: -------------------------------------------------------------------------------- 1 | 0123456789 2 | 012345 3 | 𝟘𝟙𝟚𝟛 -------------------------------------------------------------------------------- /fixtures/variables_expected/keepOnlyNotDuplicateLines: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test100 = 100; -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tyriar/vscode-sort-lines/HEAD/images/icon.png -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/keepOnlyNotDuplicateLines: -------------------------------------------------------------------------------- 1 | cc 2 | d 3 | aa 4 | c 5 | b 6 | bb 7 | a -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLines: -------------------------------------------------------------------------------- 1 | a 2 | aa 3 | b 4 | bb 5 | c 6 | cc 7 | d 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesUnique: -------------------------------------------------------------------------------- 1 | a 2 | aa 3 | b 4 | bb 5 | c 6 | cc 7 | d 8 | dd -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/removeDuplicateLines: -------------------------------------------------------------------------------- 1 | cc 2 | d 3 | aa 4 | c 5 | b 6 | bb 7 | a 8 | dd -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesNatural: -------------------------------------------------------------------------------- 1 | a 2 | aa 3 | b 4 | bb 5 | c 6 | cc 7 | d 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesReverse: -------------------------------------------------------------------------------- 1 | dd 2 | dd 3 | d 4 | cc 5 | c 6 | bb 7 | b 8 | aa 9 | a -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesShuffle: -------------------------------------------------------------------------------- 1 | cc 2 | d 3 | aa 4 | c 5 | b 6 | bb 7 | a 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesUnique: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test100 = 100; 3 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesLineLength: -------------------------------------------------------------------------------- 1 | d 2 | c 3 | b 4 | a 5 | cc 6 | aa 7 | bb 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/variables_expected/removeDuplicateLines: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test2 = 1221134; 3 | var test100 = 100; -------------------------------------------------------------------------------- /images/usage-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tyriar/vscode-sort-lines/HEAD/images/usage-animation.gif -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesCaseInsensitive: -------------------------------------------------------------------------------- 1 | a 2 | aa 3 | b 4 | bb 5 | c 6 | cc 7 | d 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesCaseInsensitiveUnique: -------------------------------------------------------------------------------- 1 | a 2 | aa 3 | b 4 | bb 5 | c 6 | cc 7 | d 8 | dd -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesLineLengthReverse: -------------------------------------------------------------------------------- 1 | cc 2 | aa 3 | bb 4 | dd 5 | dd 6 | d 7 | c 8 | b 9 | a -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesVariableLength: -------------------------------------------------------------------------------- 1 | d 2 | c 3 | b 4 | a 5 | cc 6 | aa 7 | bb 8 | dd 9 | dd -------------------------------------------------------------------------------- /fixtures/variables_fixture: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test2 = 1221134; 3 | var test100 = 100; 4 | var test2 = 1221134; -------------------------------------------------------------------------------- /images/install-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tyriar/vscode-sort-lines/HEAD/images/install-animation.gif -------------------------------------------------------------------------------- /fixtures/shuffled_lowercase_expected/sortLinesVariableLengthReverse: -------------------------------------------------------------------------------- 1 | cc 2 | aa 3 | bb 4 | dd 5 | dd 6 | d 7 | c 8 | b 9 | a -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesCaseInsensitiveUnique: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test100 = 100; 3 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLines: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test100 = 100; 3 | var test2 = 1221134; 4 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesNatural: -------------------------------------------------------------------------------- 1 | var test2 = 1221134; 2 | var test2 = 1221134; 3 | var test10 = 1; 4 | var test100 = 100; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesReverse: -------------------------------------------------------------------------------- 1 | var test2 = 1221134; 2 | var test2 = 1221134; 3 | var test100 = 100; 4 | var test10 = 1; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesShuffle: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test2 = 1221134; 3 | var test100 = 100; 4 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesLineLength: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test100 = 100; 3 | var test2 = 1221134; 4 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesCaseInsensitive: -------------------------------------------------------------------------------- 1 | var test10 = 1; 2 | var test100 = 100; 3 | var test2 = 1221134; 4 | var test2 = 1221134; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesLineLengthReverse: -------------------------------------------------------------------------------- 1 | var test2 = 1221134; 2 | var test2 = 1221134; 3 | var test100 = 100; 4 | var test10 = 1; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesVariableLength: -------------------------------------------------------------------------------- 1 | var test2 = 1221134; 2 | var test2 = 1221134; 3 | var test10 = 1; 4 | var test100 = 100; -------------------------------------------------------------------------------- /fixtures/variables_expected/sortLinesVariableLengthReverse: -------------------------------------------------------------------------------- 1 | var test100 = 100; 2 | var test10 = 1; 3 | var test2 = 1221134; 4 | var test2 = 1221134; -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | out/**/*.map 5 | src/** 6 | .gitignore 7 | tsconfig.json 8 | vsc-extension-quickstart.md 9 | tslint.json 10 | -------------------------------------------------------------------------------- /fixtures/line_length_fixture: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLines: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesNatural: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesReverse: -------------------------------------------------------------------------------- 1 | zebra 2 | trill 3 | quill 4 | puck 5 | help 6 | hello 7 | grand 8 | duck 9 | drill 10 | deck 11 | burp 12 | buck 13 | blah 14 | band 15 | back -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesShuffle: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | zebra 11 | hello 12 | help 13 | puck 14 | quill 15 | trill -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesUnique: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/removeDuplicateLines: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesLineLength: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | duck 8 | help 9 | puck 10 | drill 11 | grand 12 | hello 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/keepOnlyNotDuplicateLines: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesCaseInsensitive: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesLineLengthReverse: -------------------------------------------------------------------------------- 1 | drill 2 | grand 3 | hello 4 | quill 5 | trill 6 | zebra 7 | back 8 | band 9 | blah 10 | buck 11 | burp 12 | deck 13 | duck 14 | help 15 | puck -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesVariableLength: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | duck 8 | help 9 | puck 10 | drill 11 | grand 12 | hello 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesCaseInsensitiveUnique: -------------------------------------------------------------------------------- 1 | back 2 | band 3 | blah 4 | buck 5 | burp 6 | deck 7 | drill 8 | duck 9 | grand 10 | hello 11 | help 12 | puck 13 | quill 14 | trill 15 | zebra -------------------------------------------------------------------------------- /fixtures/line_length_expected/sortLinesVariableLengthReverse: -------------------------------------------------------------------------------- 1 | drill 2 | grand 3 | hello 4 | quill 5 | trill 6 | zebra 7 | back 8 | band 9 | blah 10 | buck 11 | burp 12 | deck 13 | duck 14 | help 15 | puck -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js'; 2 | import tseslint from 'typescript-eslint'; 3 | 4 | export default tseslint.config( 5 | eslint.configs.recommended, 6 | ...tseslint.configs.recommended, 7 | ); 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [fixtures/**/*] 12 | insert_final_newline = false 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es2018" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "noUnusedLocals": true, 12 | "strict": true 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | ".vscode-test" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "watch", 7 | "problemMatcher": "$tsc-watch", 8 | "isBackground": true, 9 | "presentation": { 10 | "reveal": "never" 11 | }, 12 | "group": { 13 | "kind": "build", 14 | "isDefault": true 15 | } 16 | }, 17 | { 18 | "type": "npm", 19 | "script": "watch-web", 20 | "group": "build", 21 | "isBackground": true, 22 | "problemMatcher": ["$ts-webpack-watch"] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ci: 7 | strategy: 8 | matrix: 9 | os: [macos-latest, ubuntu-latest, windows-latest] 10 | runs-on: ${{ matrix.os }} 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Use Node.js 20.x 14 | uses: actions/setup-node@v4 15 | with: 16 | node-version: 20.x 17 | cache: npm 18 | - name: Install and build 19 | run: | 20 | npm ci 21 | npm run compile 22 | env: 23 | CI: true 24 | - name: Test 25 | run: npm test 26 | if: runner.os != 'Linux' 27 | - name: Test on Linux 28 | run: xvfb-run -a npm test 29 | if: runner.os == 'Linux' 30 | - name: Lint 31 | run: npm run lint 32 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Use Node.js 20.x 14 | uses: actions/setup-node@v4 15 | with: 16 | node-version: 20.x 17 | registry-url: 'https://npm.pkg.github.com' 18 | cache: npm 19 | - name: Install and build 20 | run: npm ci 21 | env: 22 | CI: true 23 | - name: Build 24 | run: npm run compile 25 | env: 26 | CI: true 27 | - name: Build web 28 | run: npm run package-web 29 | env: 30 | CI: true 31 | - name: Publish with vsce 32 | run: | 33 | npm install --global @vscode/vsce 34 | # Try to publish and ignore any errors (that version was already published) 35 | vsce publish -p $VSCE_TOKEN || true 36 | env: 37 | VSCE_TOKEN: ${{ secrets.VSCE_TOKEN }} 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015, Daniel Imms (http://www.growingwiththeweb.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "npm: watch" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "npm: watch" 34 | }, 35 | { 36 | "name": "Run Web Extension in VS Code", 37 | "type": "pwa-extensionHost", 38 | "debugWebWorkerHost": true, 39 | "request": "launch", 40 | "args": [ 41 | "--extensionDevelopmentPath=${workspaceFolder}", 42 | "--extensionDevelopmentKind=web" 43 | ], 44 | "outFiles": [ 45 | "${workspaceFolder}/dist/web/**/*.js" 46 | ], 47 | "preLaunchTask": "npm: watch-web" 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as sortLines from './sort-lines'; 3 | 4 | export function activate(context: vscode.ExtensionContext): void { 5 | const commands = [ 6 | vscode.commands.registerCommand('sortLines.sortLines', sortLines.sortNormal), 7 | vscode.commands.registerCommand('sortLines.sortLinesReverse', sortLines.sortReverse), 8 | vscode.commands.registerCommand('sortLines.sortLinesCaseInsensitive', sortLines.sortCaseInsensitive), 9 | vscode.commands.registerCommand('sortLines.sortLinesCaseInsensitiveUnique', sortLines.sortCaseInsensitiveUnique), 10 | vscode.commands.registerCommand('sortLines.sortLinesLineLength', sortLines.sortLineLength), 11 | vscode.commands.registerCommand('sortLines.sortLinesLineLengthReverse', sortLines.sortLineLengthReverse), 12 | vscode.commands.registerCommand('sortLines.sortLinesVariableLength', sortLines.sortVariableLength), 13 | vscode.commands.registerCommand('sortLines.sortLinesVariableLengthReverse', sortLines.sortVariableLengthReverse), 14 | vscode.commands.registerCommand('sortLines.sortLinesNatural', sortLines.sortNatural), 15 | vscode.commands.registerCommand('sortLines.sortLinesUnique', sortLines.sortUnique), 16 | vscode.commands.registerCommand('sortLines.sortLinesShuffle', sortLines.sortShuffle), 17 | vscode.commands.registerCommand('sortLines.removeDuplicateLines', sortLines.removeDuplicateLines), 18 | vscode.commands.registerCommand('sortLines.keepOnlyDuplicateLines', sortLines.keepOnlyDuplicateLines), 19 | vscode.commands.registerCommand('sortLines.keepOnlyNotDuplicateLines', sortLines.keepOnlyNotDuplicateLines) 20 | ]; 21 | 22 | commands.forEach(command => context.subscriptions.push(command)); 23 | } 24 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | /** @typedef {import('webpack').Configuration} WebpackConfig **/ 5 | /** @type WebpackConfig */ 6 | const webExtensionConfig = { 7 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 8 | target: 'webworker', // extensions run in a webworker context 9 | entry: { 10 | extension: './src/extension.ts', // source of the web extension main file 11 | }, 12 | output: { 13 | filename: '[name].js', 14 | path: path.join(__dirname, './dist/web'), 15 | libraryTarget: 'commonjs', 16 | devtoolModuleFilenameTemplate: '../../[resource-path]' 17 | }, 18 | resolve: { 19 | mainFields: ['browser', 'module', 'main'], // look for `browser` entry point in imported node modules 20 | extensions: ['.ts', '.js'], // support ts-files and js-files 21 | alias: { 22 | // provides alternate implementation for node module and source files 23 | }, 24 | fallback: { 25 | // Webpack 5 no longer polyfills Node.js core modules automatically. 26 | // see https://webpack.js.org/configuration/resolve/#resolvefallback 27 | // for the list of Node.js core module polyfills. 28 | assert: require.resolve('assert') 29 | } 30 | }, 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.ts$/, 35 | exclude: /node_modules/, 36 | use: [ 37 | { 38 | loader: 'ts-loader' 39 | } 40 | ] 41 | } 42 | ] 43 | }, 44 | plugins: [ 45 | new webpack.ProvidePlugin({ 46 | process: 'process/browser' // provide a shim for the global `process` variable 47 | }) 48 | ], 49 | externals: { 50 | vscode: 'commonjs vscode' // ignored because it doesn't exist 51 | }, 52 | performance: { 53 | hints: false 54 | }, 55 | devtool: 'nosources-source-map' // create a source map that points to the original source file 56 | }; 57 | module.exports = [webExtensionConfig]; 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Functionality 2 | 3 | Sort lines of text in Visual Studio Code. The following types of sorting are supported: 4 | 5 | | Command | Title | Comments 6 | |---|---|---| 7 | | sortLines.sortLines | Sort lines (ascending, case sensitive) | Keybound to F9\* 8 | | sortLines.sortLinesCaseInsensitive | Sort lines (ascending, case insensitive) | 9 | | sortLines.sortLinesCaseInsensitiveUnique | Sort lines (unique ascending, case insensitive) | 10 | | sortLines.sortLinesReverse | Sort lines (descending, case sensitive) | Reverse character code based sort 11 | | sortLines.sortLinesLineLength | Sort lines (line length ascending) | 12 | | sortLines.sortLinesLineLengthReverse | Sort lines (line length descending) | 13 | | sortLines.sortLinesVariableLength | Sort lines (variable length ascending) | 14 | | sortLines.sortLinesVariableLengthReverse | Sort lines (variable length descending) | 15 | | sortLines.sortLinesNatural | Sort lines (natural) | Sorts alphabetically but groups multi-digit numbers ([Wikipedia](https://en.wikipedia.org/wiki/Natural_sort_order)) 16 | | sortLines.sortLinesUnique | Sort lines (unique ascending, case sensitive) | Regular character code keeping only unique items 17 | | sortLines.sortLinesShuffle | Sort lines (shuffle) | 18 | | sortLines.removeDuplicateLines | Sort lines (remove duplicate lines) 19 | | sortLines.keepOnlyDuplicateLines | Sort lines (keep only duplicate lines) 20 | 21 | \* *Note that this overrides the toggle breakpoint keybinding, you can unbind it by adding this to your `keybindings.json` file:* 22 | 23 | `{ "key": "f9", "command": "-sortLines.sortLines", "when": "editorTextFocus" }` 24 | 25 | # Settings 26 | 27 | | Name | Description | Default 28 | |---|---|---| 29 | | sortLines.filterBlankLines | _(boolean)_ Filter out blank (empty or whitespace-only) lines. | false 30 | | sortLines.sortEntireFile | _(boolean)_ Sort entire file if no selection is active. | false 31 | 32 | # Install 33 | 34 | 1. Open VS Code 35 | 2. Press F1 36 | 3. Type "install" 37 | 4. Select "Extensions: Install Extension". 38 | 5. Select sort-lines from the list 39 | 40 | ![Install animation](images/install-animation.gif) 41 | 42 | # Usage 43 | 44 | Select the lines to sort, press F1 type sort and select the desired sort. The regular sort has the default hotkey F9. 45 | 46 | ![Usage animation](images/usage-animation.gif) 47 | -------------------------------------------------------------------------------- /src/test/suite/sort-lines.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as path from 'path'; 3 | import * as fs from 'fs'; 4 | import { commands, window, Range, Selection, Uri, TextDocument, TextEditor } from 'vscode'; 5 | 6 | function selectAllText(editor: TextEditor): void { 7 | const selection = new Selection(0, 0, editor.document.lineCount - 1, editor.document.lineAt(editor.document.lineCount - 1).text.length); 8 | editor.selection = selection; 9 | } 10 | 11 | function getAllText(document: TextDocument): string { 12 | return document.getText(new Range(0, 0, document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length)); 13 | } 14 | 15 | const fixtureDir = path.join(__dirname, '../../../fixtures'); 16 | const fixtures = fs.readdirSync(fixtureDir).filter(v => v.search('_fixture$') !== -1).map(f => f.replace('_fixture', '')); 17 | const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../package.json'), 'utf8')); 18 | const extCommands: string[] = packageJson.contributes.commands.map((c: { command: string } | undefined) => { 19 | if (!c) { 20 | throw new Error('Command without an id encountered'); 21 | } 22 | return c.command.replace('sortLines.', ''); 23 | }); 24 | const expectedExists: { [fixture: string]: { [command: string]: boolean } } = {}; 25 | 26 | Math.random = function(): 0.9 { return 0.9; }; 27 | 28 | suite('Sort Lines', () => { 29 | suite('All command fixtures exist', () => { 30 | fixtures.forEach(fixture => { 31 | test(fixture, () => { 32 | expectedExists[fixture] = {}; 33 | extCommands.forEach(extCommand => { 34 | const exists = fs.existsSync(path.join(fixtureDir, `${fixture}_expected/${extCommand}`)); 35 | expectedExists[fixture][extCommand] = exists; 36 | assert.ok(exists, `Expected result of fixture ${fixture} for command ${extCommand} does not exist. Create the expected result in fixtures/${fixture}_expected/${extCommand}.`); 37 | }); 38 | }); 39 | }); 40 | }); 41 | 42 | extCommands.forEach(extCommand => { 43 | suite(extCommand, () => { 44 | fixtures.forEach(fixture => { 45 | test(fixture, done => { 46 | if (!expectedExists[fixture][extCommand]) { 47 | done(new Error(`Could not find expected text for fixture ${fixture}`)); 48 | return; 49 | } 50 | commands.executeCommand('workbench.action.closeActiveEditor').then(() => { 51 | return window.showTextDocument(Uri.file(path.join(fixtureDir, `${fixture}_fixture`))).then(editor => { 52 | selectAllText(editor); 53 | commands.executeCommand(`sortLines.${extCommand}`).then(() => { 54 | const expectedPath = path.join(fixtureDir, `${fixture}_expected/${extCommand}`); 55 | const expected = fs.readFileSync(expectedPath, 'utf8'); 56 | const actual = getAllText(editor.document); 57 | if (actual !== expected) { 58 | done(Error(`Command output is not expected\n\nExpected:\n${expected}\n\nActual:\n${actual}`)); 59 | } else { 60 | done(); 61 | } 62 | }); 63 | }); 64 | }); 65 | }); 66 | }); 67 | }); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.12.0 2 | 3 | - Add an editor context menu containing all commands ([#140](https://github.com/Tyriar/vscode-sort-lines/pull/140)) via [tisilent](https://github.com/tisilent) 4 | - Added `sortLines.keepOnlyNotDuplicateLines` command ([#132](https://github.com/Tyriar/vscode-sort-lines/pull/132)) via [almeidaxan](https://github.com/almeidaxan) 5 | - Fixed GitHub Actions CI ([#142](https://github.com/Tyriar/vscode-sort-lines/pull/142)) via [dotnetCarpenter](https://github.com/dotnetCarpenter) 6 | 7 | ## 1.11.0 8 | 9 | - Added `sortLines.ignoreUnselectedLastLine` which will ignore the last line if it's only selected because of the trailing \n on the previous line. This allows selecting lines to be sorted by clicking and dragging the editor line numbers ([#124](https://github.com/Tyriar/vscode-sort-lines/pull/124)) via [@gdlx](https://github.com/gdlx) 10 | 11 | ## 1.10.2 12 | 13 | - Update VS Code engine version 14 | 15 | ## 1.10.1 16 | 17 | - Fix published build artifacts 18 | 19 | ## 1.10.0 20 | 21 | - Added `sortLines.keepOnlyDuplicateLines` command which does the inverse of `sortLines.removeDuplicateLines` ([#116](https://github.com/Tyriar/vscode-sort-lines/pull/116)) via [@pit00](https://github.com/pit00) 22 | 23 | ## 1.9.1 24 | 25 | - The extension now supports vscode.dev and github.dev. 26 | 27 | ## 1.9.0 28 | 29 | - Update icon to play well with dark backgrounds ([#51](https://github.com/Tyriar/vscode-sort-lines/pull/51)) via [@Pustur](https://github.com/Pustur) 30 | - New context menu item ([#52](https://github.com/Tyriar/vscode-sort-lines/pull/52)) via [@petty](https://github.com/petty) 31 | - Add tests for shuffle sorts ([#56](https://github.com/Tyriar/vscode-sort-lines/pull/56)) via [@merelj](https://github.com/merelj) 32 | - Migrate to GitHub Actions and automate release ([#56](https://github.com/Tyriar/vscode-sort-lines/pull/60), [#61](https://github.com/Tyriar/vscode-sort-lines/pull/61), [#63](https://github.com/Tyriar/vscode-sort-lines/pull/63)) via [@Tyriar](https://github.com/Tyriar) 33 | - Upgrade to TypeScript 3.7, Mocha 6 and new VS Code test framework ([#62](https://github.com/Tyriar/vscode-sort-lines/pull/62)) via [@Tyriar](https://github.com/Tyriar) 34 | - New remove duplicate lines command ([#57](https://github.com/Tyriar/vscode-sort-lines/pull/57)) via [@merelj](https://github.com/merelj) 35 | - Enable TypeScript strict mode ([#64](https://github.com/Tyriar/vscode-sort-lines/pull/64)) via [@Tyriar](https://github.com/Tyriar) 36 | - Make sorts aware of multi-length characters ([#65](https://github.com/Tyriar/vscode-sort-lines/pull/65)) via [@Tyriar](https://github.com/Tyriar) 37 | - Make all commands use stable sorts ([#66](https://github.com/Tyriar/vscode-sort-lines/pull/66)) via [@Tyriar](https://github.com/Tyriar) 38 | 39 | ## 1.8.0 40 | 41 | - Added `sortLines.sortEntireFile` setting (defaults to false) that sorts the entire file when there is no selection [#43](https://github.com/Tyriar/vscode-sort-lines/pull/43) via [@chrsmutti](https://github.com/chrsmutti) 42 | 43 | ## 1.7.0 44 | 45 | - Added `sortLines.filterBlankLines` setting (defaults to false) [#35](https://github.com/Tyriar/vscode-sort-lines/pull/35) via [@SoftwareApe](https://github.com/SoftwareApe) 46 | 47 | ## 1.6.0 48 | 49 | - Added `sortLines.sortLinesVariableLength` and `sortLines.sortLinesVariableLengthReverse` commands to sort by variable length [#30](https://github.com/Tyriar/vscode-sort-lines/pull/30) via [@labithiotis](https://github.com/labithiotis) 50 | - Added `sortLines.sortLinesCaseInsensitiveUnique` command to sort case insensitively and remove duplicates [#29](https://github.com/Tyriar/vscode-sort-lines/pull/29) via [@lynxnake](https://github.com/lynxnake) 51 | - Convert to TypeScript 52 | - Add TSLint 53 | - Add CI 54 | - Add tests 55 | 56 | ## 1.5.0 57 | 58 | - Added `sortLines.sortLinesNatural` command sort lines alphabetically but group together digits [#26](https://github.com/Tyriar/vscode-sort-lines/pull/26) via [@Gerrit-K](https://github.com/Gerrit-K) 59 | - Remove backtick from install heading [#23](https://github.com/Tyriar/vscode-sort-lines/pull/23) via [@wald-tq](https://github.com/wald-tq) 60 | - Made a note in the README about default keybinding overriding toggle breakpoint [#22](https://github.com/Tyriar/vscode-sort-lines/issues/22) via [@Tyriar](https://github.com/Tyriar) 61 | 62 | ## 1.4.1 63 | 64 | - Added `sortLines.sortLinesLineLengthReverse` command to sort lines by line length (descending) [#21](https://github.com/Tyriar/vscode-sort-lines/pull/21) via [@prplx](https://github.com/prplx) 65 | - Improved clarity of command titles [#20](https://github.com/Tyriar/vscode-sort-lines/pull/20) via [@Eldaw](https://github.com/Eldaw) 66 | 67 | ## 1.3.0 68 | 69 | - Added `sortLines.sortLinesShuffle` command to shuffle lines randomly [#12](https://github.com/Tyriar/vscode-sort-lines/pull/12) via [@mhavas](https://github.com/mhavas). 70 | -------------------------------------------------------------------------------- /src/sort-lines.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | type ArrayTransformer = (lines: string[]) => string[]; 4 | type SortingAlgorithm = (a: string, b: string) => number; 5 | 6 | function makeSorter(algorithm?: SortingAlgorithm): ArrayTransformer { 7 | return function(lines: string[]): string[] { 8 | return lines.sort(algorithm); 9 | }; 10 | } 11 | 12 | function sortActiveSelection(transformers: ArrayTransformer[]): Thenable | undefined { 13 | const textEditor = vscode.window.activeTextEditor; 14 | if (!textEditor) { 15 | return undefined; 16 | } 17 | const selection = textEditor.selection; 18 | 19 | if (selection.isEmpty && vscode.workspace.getConfiguration('sortLines').get('sortEntireFile') === true) { 20 | return sortLines(textEditor, 0, textEditor.document.lineCount - 1, transformers); 21 | } 22 | 23 | if (selection.isSingleLine) { 24 | return undefined; 25 | } 26 | 27 | let endLine = selection.end.line; 28 | 29 | // Ignore unselected last line 30 | if (selection.end.character === 0 && vscode.workspace.getConfiguration('sortLines').get('ignoreUnselectedLastLine') === true) { 31 | endLine -= 1; 32 | } 33 | return sortLines(textEditor, selection.start.line, endLine, transformers); 34 | } 35 | 36 | function sortLines(textEditor: vscode.TextEditor, startLine: number, endLine: number, transformers: ArrayTransformer[]): Thenable { 37 | let lines: string[] = []; 38 | for (let i = startLine; i <= endLine; i++) { 39 | lines.push(textEditor.document.lineAt(i).text); 40 | } 41 | 42 | // Remove blank lines in selection 43 | if (vscode.workspace.getConfiguration('sortLines').get('filterBlankLines') === true) { 44 | removeBlanks(lines); 45 | } 46 | 47 | lines = transformers.reduce((currentLines, transform) => transform(currentLines), lines); 48 | 49 | return textEditor.edit(editBuilder => { 50 | const range = new vscode.Range(startLine, 0, endLine, textEditor.document.lineAt(endLine).text.length); 51 | editBuilder.replace(range, lines.join('\n')); 52 | }); 53 | } 54 | 55 | function removeDuplicates(lines: string[]): string[] { 56 | return Array.from(new Set(lines)); 57 | } 58 | 59 | function keepOnlyDuplicates(lines: string[]): string[] { 60 | return Array.from(new Set(lines.filter((element, index, array) => array.indexOf(element) !== index))); 61 | } 62 | 63 | function keepOnlyNotDuplicates(lines: string[]): string[] { 64 | return Array.from(new Set(lines.filter((element, index, array) => (array.lastIndexOf(element) === array.indexOf(element))))); 65 | } 66 | 67 | function removeBlanks(lines: string[]): void { 68 | for (let i = 0; i < lines.length; ++i) { 69 | if (lines[i].trim() === '') { 70 | lines.splice(i, 1); 71 | i--; 72 | } 73 | } 74 | } 75 | 76 | function reverseCompare(a: string, b: string): number { 77 | if (a === b) { 78 | return 0; 79 | } 80 | return a < b ? 1 : -1; 81 | } 82 | 83 | function caseInsensitiveCompare(a: string, b: string): number { 84 | return a.localeCompare(b, undefined, {sensitivity: 'base'}); 85 | } 86 | 87 | function lineLengthCompare(a: string, b: string): number { 88 | // Use Array.from so that multi-char characters count as 1 each 89 | const aLength = Array.from(a).length; 90 | const bLength = Array.from(b).length; 91 | if (aLength === bLength) { 92 | return 0; 93 | } 94 | return aLength > bLength ? 1 : -1; 95 | } 96 | 97 | function lineLengthReverseCompare(a: string, b: string): number { 98 | return lineLengthCompare(a, b) * -1; 99 | } 100 | 101 | function variableLengthCompare(a: string, b: string): number { 102 | return lineLengthCompare(getVariableCharacters(a), getVariableCharacters(b)); 103 | } 104 | 105 | function variableLengthReverseCompare(a: string, b: string): number { 106 | return variableLengthCompare(a, b) * -1; 107 | } 108 | 109 | let intlCollator: Intl.Collator; 110 | function naturalCompare(a: string, b: string): number { 111 | if (!intlCollator) { 112 | intlCollator = new Intl.Collator(undefined, {numeric: true}); 113 | } 114 | return intlCollator.compare(a, b); 115 | } 116 | 117 | function getVariableCharacters(line: string): string { 118 | const match = line.match(/(.*)=/); 119 | if (!match) { 120 | return line; 121 | } 122 | const last = match.pop(); 123 | if (!last) { 124 | return line; 125 | } 126 | return last; 127 | } 128 | 129 | function shuffleSorter(lines: string[]): string[] { 130 | for (let i = lines.length - 1; i > 0; i--) { 131 | const rand = Math.floor(Math.random() * (i + 1)); 132 | [lines[i], lines[rand]] = [lines[rand], lines[i]]; 133 | } 134 | return lines; 135 | } 136 | 137 | const transformerSequences = { 138 | sortNormal: [makeSorter()], 139 | sortUnique: [makeSorter(), removeDuplicates], 140 | sortReverse: [makeSorter(reverseCompare)], 141 | sortCaseInsensitive: [makeSorter(caseInsensitiveCompare)], 142 | sortCaseInsensitiveUnique: [makeSorter(caseInsensitiveCompare), removeDuplicates], 143 | sortLineLength: [makeSorter(lineLengthCompare)], 144 | sortLineLengthReverse: [makeSorter(lineLengthReverseCompare)], 145 | sortVariableLength: [makeSorter(variableLengthCompare)], 146 | sortVariableLengthReverse: [makeSorter(variableLengthReverseCompare)], 147 | sortNatural: [makeSorter(naturalCompare)], 148 | sortShuffle: [shuffleSorter], 149 | removeDuplicateLines: [removeDuplicates], 150 | keepOnlyDuplicateLines: [keepOnlyDuplicates], 151 | keepOnlyNotDuplicateLines: [keepOnlyNotDuplicates] 152 | }; 153 | 154 | export const sortNormal = () => sortActiveSelection(transformerSequences.sortNormal); 155 | export const sortUnique = () => sortActiveSelection(transformerSequences.sortUnique); 156 | export const sortReverse = () => sortActiveSelection(transformerSequences.sortReverse); 157 | export const sortCaseInsensitive = () => sortActiveSelection(transformerSequences.sortCaseInsensitive); 158 | export const sortCaseInsensitiveUnique = () => sortActiveSelection(transformerSequences.sortCaseInsensitiveUnique); 159 | export const sortLineLength = () => sortActiveSelection(transformerSequences.sortLineLength); 160 | export const sortLineLengthReverse = () => sortActiveSelection(transformerSequences.sortLineLengthReverse); 161 | export const sortVariableLength = () => sortActiveSelection(transformerSequences.sortVariableLength); 162 | export const sortVariableLengthReverse = () => sortActiveSelection(transformerSequences.sortVariableLengthReverse); 163 | export const sortNatural = () => sortActiveSelection(transformerSequences.sortNatural); 164 | export const sortShuffle = () => sortActiveSelection(transformerSequences.sortShuffle); 165 | export const removeDuplicateLines = () => sortActiveSelection(transformerSequences.removeDuplicateLines); 166 | export const keepOnlyDuplicateLines = () => sortActiveSelection(transformerSequences.keepOnlyDuplicateLines); 167 | export const keepOnlyNotDuplicateLines = () => sortActiveSelection(transformerSequences.keepOnlyNotDuplicateLines); 168 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sort-lines", 3 | "displayName": "Sort lines", 4 | "description": "Sorts lines of text", 5 | "version": "1.12.0", 6 | "license": "MIT", 7 | "bugs": { 8 | "url": "https://github.com/Tyriar/vscode-sort-lines/issues" 9 | }, 10 | "type": "commonjs", 11 | "scripts": { 12 | "vscode:prepublish": "npm run compile", 13 | "compile": "tsc -p ./", 14 | "lint": "eslint ./src/*.ts", 15 | "watch": "tsc -watch -p ./", 16 | "pretest": "npm run compile", 17 | "test": "node ./out/test/runTest.js", 18 | "compile-web": "webpack", 19 | "watch-web": "webpack --watch", 20 | "package-web": "webpack --mode production --devtool hidden-source-map" 21 | }, 22 | "homepage": "https://github.com/Tyriar/vscode-sort-lines", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/Tyriar/vscode-sort-lines" 26 | }, 27 | "publisher": "Tyriar", 28 | "engines": { 29 | "vscode": "^1.79.0" 30 | }, 31 | "categories": [ 32 | "Other" 33 | ], 34 | "activationEvents": [], 35 | "main": "./out/extension", 36 | "browser": "./dist/web/extension.js", 37 | "contributes": { 38 | "commands": [ 39 | { 40 | "command": "sortLines.sortLines", 41 | "title": "Sort lines (ascending, case sensitive)" 42 | }, 43 | { 44 | "command": "sortLines.sortLinesCaseInsensitive", 45 | "title": "Sort lines (ascending, case insensitive)" 46 | }, 47 | { 48 | "command": "sortLines.sortLinesCaseInsensitiveUnique", 49 | "title": "Sort lines (unique ascending, case insensitive)" 50 | }, 51 | { 52 | "command": "sortLines.sortLinesReverse", 53 | "title": "Sort lines (descending, case sensitive)" 54 | }, 55 | { 56 | "command": "sortLines.sortLinesLineLength", 57 | "title": "Sort lines (line length ascending)" 58 | }, 59 | { 60 | "command": "sortLines.sortLinesLineLengthReverse", 61 | "title": "Sort lines (line length descending)" 62 | }, 63 | { 64 | "command": "sortLines.sortLinesVariableLength", 65 | "title": "Sort lines (variable length ascending)" 66 | }, 67 | { 68 | "command": "sortLines.sortLinesVariableLengthReverse", 69 | "title": "Sort lines (variable length descending)" 70 | }, 71 | { 72 | "command": "sortLines.sortLinesNatural", 73 | "title": "Sort lines (natural)" 74 | }, 75 | { 76 | "command": "sortLines.sortLinesUnique", 77 | "title": "Sort lines (unique ascending, case sensitive)" 78 | }, 79 | { 80 | "command": "sortLines.removeDuplicateLines", 81 | "title": "Sort lines (remove duplicate lines)" 82 | }, 83 | { 84 | "command": "sortLines.keepOnlyDuplicateLines", 85 | "title": "Sort lines (keep only duplicated lines)" 86 | }, 87 | { 88 | "command": "sortLines.keepOnlyNotDuplicateLines", 89 | "title": "Sort lines (keep only not duplicated lines)" 90 | }, 91 | { 92 | "command": "sortLines.sortLinesShuffle", 93 | "title": "Sort lines (shuffle)" 94 | } 95 | ], 96 | "configuration": { 97 | "type": "object", 98 | "title": "Sort Lines", 99 | "properties": { 100 | "sortLines.filterBlankLines": { 101 | "type": "boolean", 102 | "default": false, 103 | "description": "Filter out blank (empty or whitespace-only) lines." 104 | }, 105 | "sortLines.ignoreUnselectedLastLine": { 106 | "type": "boolean", 107 | "default": false, 108 | "description": "Ignore unselected last line. Allows selection by line numbers." 109 | }, 110 | "sortLines.sortEntireFile": { 111 | "type": "boolean", 112 | "default": false, 113 | "description": "Sort entire file if no selection is active." 114 | } 115 | } 116 | }, 117 | "keybindings": [ 118 | { 119 | "command": "sortLines.sortLines", 120 | "key": "f9", 121 | "when": "editorTextFocus" 122 | } 123 | ], 124 | "menus": { 125 | "editor/context": [ 126 | { 127 | "command": "sortLines.sortLines", 128 | "when": "editorTextFocus && !editorReadonly", 129 | "group": "sortLines@1" 130 | }, 131 | { 132 | "submenu": "sortLines", 133 | "when": "editorTextFocus && !editorReadonly", 134 | "group": "sortLines@2" 135 | } 136 | ], 137 | "sortLines": [ 138 | { 139 | "command": "sortLines.sortLines", 140 | "group": "2_sortLines@1" 141 | }, 142 | { 143 | "command": "sortLines.sortLinesCaseInsensitive", 144 | "group": "2_sortLines@2" 145 | }, 146 | { 147 | "command": "sortLines.sortLinesCaseInsensitiveUnique", 148 | "group": "2_sortLines@3" 149 | }, 150 | { 151 | "command": "sortLines.sortLinesReverse", 152 | "group": "2_sortLines@4" 153 | }, 154 | { 155 | "command": "sortLines.sortLinesLineLength", 156 | "group": "2_sortLines@5" 157 | }, 158 | { 159 | "command": "sortLines.sortLinesLineLengthReverse", 160 | "group": "2_sortLines@6" 161 | }, 162 | { 163 | "command": "sortLines.sortLinesVariableLength", 164 | "group": "2_sortLines@7" 165 | }, 166 | { 167 | "command": "sortLines.sortLinesVariableLengthReverse", 168 | "group": "2_sortLines@8" 169 | }, 170 | { 171 | "command": "sortLines.sortLinesNatural", 172 | "group": "2_sortLines@9" 173 | }, 174 | { 175 | "command": "sortLines.sortLinesUnique", 176 | "group": "2_sortLines@10" 177 | }, 178 | { 179 | "command": "sortLines.removeDuplicateLines", 180 | "group": "2_sortLines@11" 181 | }, 182 | { 183 | "command": "sortLines.keepOnlyDuplicateLines", 184 | "group": "2_sortLines@12" 185 | }, 186 | { 187 | "command": "sortLines.keepOnlyNotDuplicateLines", 188 | "group": "2_sortLines@13" 189 | }, 190 | { 191 | "command": "sortLines.sortLinesShuffle", 192 | "group": "2_sortLines@14" 193 | } 194 | ] 195 | }, 196 | "submenus": [ 197 | { 198 | "id": "sortLines", 199 | "label": "Sort lines" 200 | } 201 | ] 202 | }, 203 | "devDependencies": { 204 | "@eslint/js": "^9.14.0", 205 | "@types/eslint__js": "^8.42.3", 206 | "@types/glob": "^8.1.0", 207 | "@types/mocha": "^10.0.9", 208 | "@types/node": "^20.14.8", 209 | "@types/vscode": "^1.95.0", 210 | "@types/webpack-env": "^1.18.5", 211 | "@vscode/test-electron": "^2.4.1", 212 | "eslint": "^9.14.0", 213 | "mocha": "^10.8.2", 214 | "ts-loader": "^9.5.1", 215 | "typescript-eslint": "^8.13.0", 216 | "typescript": "^5.6.3", 217 | "webpack-cli": "^5.1.4", 218 | "webpack": "^5.96.1" 219 | }, 220 | "icon": "images/icon.png" 221 | } 222 | --------------------------------------------------------------------------------