trimTrailingWhitespaceCommand.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as strings from '../../../base/common/strings.js';
  6. import { EditOperation } from '../core/editOperation.js';
  7. import { Range } from '../core/range.js';
  8. export class TrimTrailingWhitespaceCommand {
  9. constructor(selection, cursors) {
  10. this._selection = selection;
  11. this._cursors = cursors;
  12. this._selectionId = null;
  13. }
  14. getEditOperations(model, builder) {
  15. let ops = trimTrailingWhitespace(model, this._cursors);
  16. for (let i = 0, len = ops.length; i < len; i++) {
  17. let op = ops[i];
  18. builder.addEditOperation(op.range, op.text);
  19. }
  20. this._selectionId = builder.trackSelection(this._selection);
  21. }
  22. computeCursorState(model, helper) {
  23. return helper.getTrackedSelection(this._selectionId);
  24. }
  25. }
  26. /**
  27. * Generate commands for trimming trailing whitespace on a model and ignore lines on which cursors are sitting.
  28. */
  29. export function trimTrailingWhitespace(model, cursors) {
  30. // Sort cursors ascending
  31. cursors.sort((a, b) => {
  32. if (a.lineNumber === b.lineNumber) {
  33. return a.column - b.column;
  34. }
  35. return a.lineNumber - b.lineNumber;
  36. });
  37. // Reduce multiple cursors on the same line and only keep the last one on the line
  38. for (let i = cursors.length - 2; i >= 0; i--) {
  39. if (cursors[i].lineNumber === cursors[i + 1].lineNumber) {
  40. // Remove cursor at `i`
  41. cursors.splice(i, 1);
  42. }
  43. }
  44. let r = [];
  45. let rLen = 0;
  46. let cursorIndex = 0;
  47. let cursorLen = cursors.length;
  48. for (let lineNumber = 1, lineCount = model.getLineCount(); lineNumber <= lineCount; lineNumber++) {
  49. let lineContent = model.getLineContent(lineNumber);
  50. let maxLineColumn = lineContent.length + 1;
  51. let minEditColumn = 0;
  52. if (cursorIndex < cursorLen && cursors[cursorIndex].lineNumber === lineNumber) {
  53. minEditColumn = cursors[cursorIndex].column;
  54. cursorIndex++;
  55. if (minEditColumn === maxLineColumn) {
  56. // The cursor is at the end of the line => no edits for sure on this line
  57. continue;
  58. }
  59. }
  60. if (lineContent.length === 0) {
  61. continue;
  62. }
  63. let lastNonWhitespaceIndex = strings.lastNonWhitespaceIndex(lineContent);
  64. let fromColumn = 0;
  65. if (lastNonWhitespaceIndex === -1) {
  66. // Entire line is whitespace
  67. fromColumn = 1;
  68. }
  69. else if (lastNonWhitespaceIndex !== lineContent.length - 1) {
  70. // There is trailing whitespace
  71. fromColumn = lastNonWhitespaceIndex + 2;
  72. }
  73. else {
  74. // There is no trailing whitespace
  75. continue;
  76. }
  77. fromColumn = Math.max(minEditColumn, fromColumn);
  78. r[rLen++] = EditOperation.delete(new Range(lineNumber, fromColumn, lineNumber, maxLineColumn));
  79. }
  80. return r;
  81. }