Exemple #1
0
export function normalizeMessages(linterName: string, messages: Array<Message>) {
  for (let i = 0, length = messages.length; i < length; ++i) {
    const message = messages[i]
    const reference = message.reference
    if (Array.isArray(message.location.position)) {
      message.location.position = Range.fromObject(message.location.position)
    }
    if (reference && Array.isArray(reference.position)) {
      reference.position = Point.fromObject(reference.position)
    }
    if (message.solutions && message.solutions.length) {
      for (let j = 0, _length = message.solutions.length, solution; j < _length; j++) {
        solution = message.solutions[j]
        if (Array.isArray(solution.position)) {
          solution.position = Range.fromObject(solution.position)
        }
      }
    }
    message.version = 2
    message.linterName = linterName
    message.key = messageKey(message)
  }
}
Exemple #2
0
  getPoint(cursor, countState) {
    const {direction} = this
    let {which} = this
    const regex = this.name.endsWith("Subword") ? cursor.subwordRegExp() : this.wordRegex || cursor.wordRegExp()

    const options = this.buildOptions(cursor)
    if (direction === "next" && which === "start" && this.operator && countState.isFinal) {
      // [NOTE] Exceptional behavior for w and W: [Detail in vim help `:help w`.]
      // [case-A] cw, cW treated as ce, cE when cursor is at non-blank.
      // [case-B] when w, W used as TARGET, it doesn't move over new line.
      const {from} = options
      if (this.isEmptyRow(from.row)) return [from.row + 1, 0]

      // [case-A]
      if (this.operator.name === "Change" && !this.utils.pointIsAtWhiteSpace(this.editor, from)) {
        which = "end"
      }
      const point = this.findPoint(direction, regex, which, options)
      // [case-B]
      return point ? Point.min(point, [from.row, Infinity]) : this.getFirstOrLastPoint(direction)
    } else {
      return this.findPoint(direction, regex, which, options) || this.getFirstOrLastPoint(direction)
    }
  }
 it('does not insert an open bracket when completing a balanced nested expression', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('[[self foo] setEnabled:NO]'),
     Point.fromObject([0, 25])
   )).toEqual(null);
 });
 it('inserts an open bracket at the beginning of an unbalanced nested expression', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('[self foo] setEnabled:NO]'),
     Point.fromObject([0, 24])
   )).toEqual(Point.fromObject([0, 0]));
 });
 it('inserts an open bracket at the start of an unbalanced simple expression', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('self setEnabled:NO]'),
     Point.fromObject([0, 18])
   )).toEqual(Point.fromObject([0, 0]));
 });
      editor.transact(() => {
        // Temporarily disable autocomplete suggestions.
        this.suggestionsEnabled = false;
        const selectedRange = editor.getSelectedBufferRange();
        const selectionMarker = editor.markBufferRange(selectedRange);
        const selectedText = editor.getSelectedText();
        const placeholder = 'var';
        // Look for top-level position.
        let topLevelRange = new Range([0, 0], [0, 0]);
        editor.backwardsScanInBufferRange(
          helper.topLevelRegex(),
          [[0, 0], editor.getCursorBufferPosition()],
          ({ range, stop }) => {
            stop();
            topLevelRange = range;
          }
        );
        // Look for var or "in" above.
        const varOrInRegex = /(\s(\S+)\s*=\s*$)|(\s(in)\s*$)/;
        let varRange = topLevelRange;
        let gotInInsteadOfVar = false;
        editor.backwardsScanInBufferRange(
          varOrInRegex,
          [topLevelRange.start, selectedRange.start],
          ({ match, range, stop }) => {
            if (match && match.length > 4) {
              stop();
              varRange = range;
              if (match[4] === 'in') {
                gotInInsteadOfVar = true;
              }
            }
          }
        );
        // Look for "let" or "in" above.
        let inRange = null;
        let inMarker = null;
        let inIsAbove = true;
        let letOrInMatchText = null;
        const letOrInRegex = /\s(let|in)\s*$/g;

        if (gotInInsteadOfVar) {
          inRange = varRange;
          inMarker = editor.markBufferRange(inRange);
          letOrInMatchText = 'in';
        } else {
          editor.backwardsScanInBufferRange(
            letOrInRegex,
            [topLevelRange.start, varRange.start],
            ({ match, range, stop }) => {
              if (match && match.length > 1) {
                if (range.start.column < varRange.start.column) {
                  stop();
                  inRange = range;
                  inMarker = editor.markBufferRange(inRange);
                  letOrInMatchText = match[1];
                }
              }
            }
          );
        }

        if (!inRange || letOrInMatchText === 'let') {
          // Look for next top-level position (to determine search bounds).
          let nextTopLevelRange = new Range(
            editor.getEofBufferPosition(),
            editor.getEofBufferPosition()
          );
          editor.scanInBufferRange(
            helper.blockRegex(),
            [selectedRange.end, editor.getEofBufferPosition()],
            ({ range, stop }) => {
              stop();
              nextTopLevelRange = range;
            }
          );
          // Look for "in" below, skipping let-in pairs.
          inRange = null;
          let numLetInPairs = 0;
          editor.scanInBufferRange(
            letOrInRegex,
            [selectedRange.end, nextTopLevelRange.start],
            ({ match, range, stop }) => {
              if (match && match.length > 1) {
                if (match[1] === 'let') {
                  ++numLetInPairs;
                } else if (match[1] === 'in') {
                  if (numLetInPairs > 0) {
                    --numLetInPairs;
                  } else {
                    stop();
                    inRange = range;
                    inMarker = editor.markBufferRange(range);
                    inIsAbove = false;
                  }
                }
              }
            }
          );
        }
        if (inRange) {
          // Found an "in" above or below.
          const leadingSpaces = new Array(inRange.start.column + 2).join(' ');
          const selectedLines = selectedText.split('\n');
          editor.setCursorBufferPosition(inRange.start);
          editor.insertText(
            '\n' +
              leadingSpaces +
              helper.tabSpaces() +
              placeholder +
              ' =\n' +
              leadingSpaces +
              helper.tabSpaces() +
              (inIsAbove
                ? selectedLines
                    .map(text => {
                      return helper.tabSpaces() + text;
                    })
                    .join('\n')
                : helper.tabSpaces() +
                  selectedLines
                    .map(text => {
                      return text;
                    })
                    .join('\n')) +
              '\n' +
              new Array(inRange.start.column + 1).join(' ')
          );
          editor.setTextInBufferRange(
            selectionMarker.getBufferRange(),
            placeholder
          );
          const offset1 =
            inMarker.getBufferRange().start.row -
            (selectedLines.length - 1) +
            selectedLines.length;
          const cursorPosition1 = new Point(
            offset1,
            leadingSpaces.length + helper.tabSpaces().length
          );
          editor.setSelectedBufferRanges([
            selectionMarker.getBufferRange(),
            [
              cursorPosition1,
              cursorPosition1.translate([0, placeholder.length]),
            ],
          ]);
          inMarker.destroy();
        } else {
          // No `let/in` found.  Wrap function body in a `let/in` instead.
          let bodyRange;
          editor.scanInBufferRange(
            /=\s*\n/,
            [topLevelRange.start, editor.getEofBufferPosition()],
            ({ range, stop }) => {
              stop();
              bodyRange = range;
            }
          );
          if (bodyRange) {
            const leadingSpaces = helper.tabSpaces();
            // Insert leading spaces on top-level body.
            let row = bodyRange.end.row;
            while (row <= topLevelRange.end.row + 1) {
              editor.setCursorBufferPosition([row, 0]);
              editor.insertText(leadingSpaces);
              ++row;
            }
            editor.setCursorBufferPosition(bodyRange.end);
            editor.insertText(
              leadingSpaces +
                'let\n' +
                leadingSpaces +
                helper.tabSpaces() +
                placeholder +
                ' =\n' +
                leadingSpaces +
                selectedText
                  .split('\n')
                  .map(text => {
                    return leadingSpaces + helper.tabSpaces() + text;
                  })
                  .join('\n') +
                '\n' +
                leadingSpaces +
                'in\n'
            );
            editor.setTextInBufferRange(
              selectionMarker.getBufferRange(),
              placeholder
            );
            const cursorPosition1 = new Point(
              bodyRange.start.row + 2,
              leadingSpaces.length + helper.tabSpaces().length
            );
            editor.setSelectedBufferRanges([
              selectionMarker.getBufferRange(),
              [
                cursorPosition1,
                cursorPosition1.translate([0, placeholder.length]),
              ],
            ]);
          } else {
            atom.notifications.addError(
              "Sorry, I don't know how to lift that."
            );
          }
        }
        this.handleEndOfAct(editor);
        selectionMarker.destroy();
      });
Exemple #7
0
function pointIsAtEndOfLineAtNonEmptyRow (editor, point) {
  point = Point.fromObject(point)
  return point.column > 0 && pointIsAtEndOfLine(editor, point)
}
Exemple #8
0
function traverseTextFromPoint (point, text) {
  return Point.fromObject(point).traverse(getTraversalForText(text))
}
   + ' open bracket in a char literal', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer("[foo('[') setEnabled:NO]"),
     Point.fromObject([0, 23])
   )).toEqual(null);
 });
 it('returns null for single-line method calls', () => {
   expect(getIndentedColonColumn(
       new TextBuffer('[obj arg:value :'),
       Point.fromObject([0, 15])))
       .toBeNull();
 });
 expect(() => getIndentedColonColumn(new TextBuffer(': '), Point.fromObject([0, 1])))
Exemple #12
0
function validateMessages(linterName: string, entries: Array<Message>): boolean {
  const messages = []

  if (Array.isArray(entries)) {
    let invalidURL = false
    let invalidIcon = false
    let invalidExcerpt = false
    let invalidLocation = false
    let invalidSeverity = false
    let invalidSolution = false
    let invalidReference = false
    let invalidDescription = false
    let invalidLinterName = false

    for (let i = 0, { length } = entries; i < length; ++i) {
      const message = entries[i]
      const { reference } = message
      if (!invalidIcon && message.icon && typeof message.icon !== 'string') {
        invalidIcon = true
        messages.push('Message.icon must be a string')
      }
      if (
        !invalidLocation &&
        (!message.location ||
          typeof message.location !== 'object' ||
          typeof message.location.file !== 'string' ||
          typeof message.location.position !== 'object' ||
          !message.location.position)
      ) {
        invalidLocation = true
        messages.push('Message.location must be valid')
      } else if (!invalidLocation) {
        const range = Range.fromObject(message.location.position)
        if (
          Number.isNaN(range.start.row) ||
          Number.isNaN(range.start.column) ||
          Number.isNaN(range.end.row) ||
          Number.isNaN(range.end.column)
        ) {
          invalidLocation = true
          messages.push('Message.location.position should not contain NaN coordinates')
        }
      }
      if (!invalidSolution && message.solutions && !Array.isArray(message.solutions)) {
        invalidSolution = true
        messages.push('Message.solutions must be valid')
      }
      if (
        !invalidReference &&
        reference &&
        (typeof reference !== 'object' ||
          typeof reference.file !== 'string' ||
          typeof reference.position !== 'object' ||
          !reference.position)
      ) {
        invalidReference = true
        messages.push('Message.reference must be valid')
      } else if (!invalidReference && reference) {
        const position = Point.fromObject(reference.position)
        if (Number.isNaN(position.row) || Number.isNaN(position.column)) {
          invalidReference = true
          messages.push('Message.reference.position should not contain NaN coordinates')
        }
      }
      if (!invalidExcerpt && typeof message.excerpt !== 'string') {
        invalidExcerpt = true
        messages.push('Message.excerpt must be a string')
      }
      if (!invalidSeverity && !VALID_SEVERITY.has(message.severity)) {
        invalidSeverity = true
        messages.push("Message.severity must be 'error', 'warning' or 'info'")
      }
      if (!invalidURL && message.url && typeof message.url !== 'string') {
        invalidURL = true
        messages.push('Message.url must be a string')
      }
      if (
        !invalidDescription &&
        message.description &&
        typeof message.description !== 'function' &&
        typeof message.description !== 'string'
      ) {
        invalidDescription = true
        messages.push('Message.description must be a function or string')
      }
      if (!invalidLinterName && message.linterName && typeof message.linterName !== 'string') {
        invalidLinterName = true
        messages.push('Message.linterName must be a string')
      }
    }
  } else {
    messages.push('Linter Result must be an Array')
  }

  if (messages.length) {
    showError(
      'Invalid Linter Result received',
      `These issues were encountered while processing messages from a linter named '${linterName}'`,
      messages,
    )
    return false
  }

  return true
}
Exemple #13
0
export function linterMessageV2ToDiagnosticMessage(
  msg: LinterMessageV2,
  providerName: string,
): DiagnosticMessage {
  let trace;
  if (msg.trace != null) {
    trace = msg.trace.map(convertLinterTrace);
  } else if (msg.reference != null) {
    const point =
      msg.reference.position != null
        ? Point.fromObject(msg.reference.position)
        : null;
    trace = [
      {
        type: 'Trace',
        text: 'Reference',
        filePath: msg.reference.file,
        range: point ? new Range(point, point) : undefined,
      },
    ];
  }
  let fix;
  const actions = [];
  const {solutions} = msg;
  if (solutions != null && solutions.length > 0) {
    const sortedSolutions = Array.from(solutions).sort(
      (a, b) => (a.priority || 0) - (b.priority || 0),
    );
    sortedSolutions.forEach((solution, i) => {
      if (solution.replaceWith !== undefined) {
        // TODO: support multiple fixes.
        if (fix == null) {
          fix = {
            oldRange: Range.fromObject(solution.position),
            oldText: solution.currentText,
            newText: solution.replaceWith,
            title: solution.title,
          };
        }
      } else {
        actions.push({
          title: solution.title != null ? solution.title : `Solution ${i + 1}`,
          apply: solution.apply.bind(solution),
        });
      }
    });
  }
  let text = msg.excerpt;
  // TODO: use markdown + handle callback-based version.
  if (typeof msg.description === 'string') {
    text = text + '\n' + msg.description;
  }
  return {
    // flowlint-next-line sketchy-null-string:off
    providerName: msg.linterName || providerName,
    type: convertLinterType(msg.severity),
    filePath: msg.location.file,
    text,
    kind: msg.kind,
    range: Range.fromObject(msg.location.position),
    trace,
    fix,
    actions,
  };
}
function validateMessages(linterName, entries) {
  var messages = [];

  if (Array.isArray(entries)) {
    var invalidURL = false;
    var invalidIcon = false;
    var invalidExcerpt = false;
    var invalidLocation = false;
    var invalidSeverity = false;
    var invalidSolution = false;
    var invalidReference = false;
    var invalidDescription = false;
    var invalidLinterName = false;

    for (var i = 0, _length = entries.length; i < _length; ++i) {
      var message = entries[i];
      var reference = message.reference;
      if (!invalidIcon && message.icon && typeof message.icon !== 'string') {
        invalidIcon = true;
        messages.push('Message.icon must be a string');
      }
      if (!invalidLocation && (!message.location || typeof message.location !== 'object' || typeof message.location.file !== 'string' || typeof message.location.position !== 'object' || !message.location.position)) {
        invalidLocation = true;
        messages.push('Message.location must be valid');
      } else if (!invalidLocation) {
        var range = _atom.Range.fromObject(message.location.position);
        if (Number.isNaN(range.start.row) || Number.isNaN(range.start.column) || Number.isNaN(range.end.row) || Number.isNaN(range.end.column)) {
          invalidLocation = true;
          messages.push('Message.location.position should not contain NaN coordinates');
        }
      }
      if (!invalidSolution && message.solutions && !Array.isArray(message.solutions)) {
        invalidSolution = true;
        messages.push('Message.solutions must be valid');
      }
      if (!invalidReference && reference && (typeof reference !== 'object' || typeof reference.file !== 'string' || typeof reference.position !== 'object' || !reference.position)) {
        invalidReference = true;
        messages.push('Message.reference must be valid');
      } else if (!invalidReference && reference) {
        var position = _atom.Point.fromObject(reference.position);
        if (Number.isNaN(position.row) || Number.isNaN(position.column)) {
          invalidReference = true;
          messages.push('Message.reference.position should not contain NaN coordinates');
        }
      }
      if (!invalidExcerpt && typeof message.excerpt !== 'string') {
        invalidExcerpt = true;
        messages.push('Message.excerpt must be a string');
      }
      if (!invalidSeverity && !VALID_SEVERITY.has(message.severity)) {
        invalidSeverity = true;
        messages.push("Message.severity must be 'error', 'warning' or 'info'");
      }
      if (!invalidURL && message.url && typeof message.url !== 'string') {
        invalidURL = true;
        messages.push('Message.url must be a string');
      }
      if (!invalidDescription && message.description && typeof message.description !== 'function' && typeof message.description !== 'string') {
        invalidDescription = true;
        messages.push('Message.description must be a function or string');
      }
      if (!invalidLinterName && message.linterName && typeof message.linterName !== 'string') {
        invalidLinterName = true;
        messages.push('Message.linterName must be a string');
      }
    }
  } else {
    messages.push('Linter Result must be an Array');
  }

  if (messages.length) {
    (0, _helpers.showError)('Invalid Linter Result received', 'These issues were encountered while processing messages from a linter named \'' + linterName + '\'', messages);
    return false;
  }

  return true;
}
   + ' bracket in a string literal', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('[self fooWithBar:@"tricky ["] setEnabled:NO]'),
     Point.fromObject([0, 43])
   )).toEqual(Point.fromObject([0, 0]));
 });
  static getOpenBracketInsertPosition(
    buffer: atom$TextBuffer,
    closeBracketPosition: Point,
  ): ?Point {
    const startingLine = buffer.lineForRow(closeBracketPosition.row);
    let singleQuoteCount = 0;
    let doubleQuoteCount = 0;
    const characterCount = {
      '[': 0,
      ']': 0,
    };

    // Iterate through the line, determining if we have balanced brackets.
    // We do not count brackets we encounter inside string/char literals.
    for (let i = 0; i < startingLine.length; i++) {
      if (startingLine[i] === '\'') {
        singleQuoteCount++;
      } else if (startingLine[i] === '"') {
        doubleQuoteCount++;
      } else {
        if (singleQuoteCount % 2 === 0 && doubleQuoteCount % 2 === 0) {
          // We are not inside a char nor string literal. Count the brackets.
          characterCount[startingLine[i]]++;
        }
      }
    }

    const stringLiteralMatch = /@".*"\s.*]/.exec(startingLine);
    if (stringLiteralMatch) {
      return Point.fromObject([closeBracketPosition.row, stringLiteralMatch.index]);
    } else if (characterCount['['] < characterCount[']']) {
      // Check if we're at the bottom of a multi-line method.
      const multiLineMethodRegex = /^[\s\w\[]*:.*[^;{];?$/;
      let currentRow = closeBracketPosition.row;
      let currentRowPlusOne = null;
      let match = multiLineMethodRegex.exec(buffer.lineForRow(currentRow));

      while (match !== null) {
        currentRowPlusOne = currentRow;
        match = multiLineMethodRegex.exec(buffer.lineForRow(--currentRow));
      }

      if (currentRowPlusOne !== null && currentRowPlusOne !== closeBracketPosition.row) {
        const targetLine = buffer.lineForRow(currentRowPlusOne);
        const targetMatch = /\S/.exec(targetLine);

        if (targetLine[targetMatch.index] === '[') {
          return null;
        } else {
          return Point.fromObject([currentRowPlusOne, targetMatch.index]);
        }
      } else {
        // We need a bracket on this line - at this point it's either
        // At the beginning, or after an `=`.
        const initMatch = /.*(=\s?)\S/.exec(startingLine);
        const startOfLineMatch = /\S/.exec(startingLine);
        let column = 0;

        if (initMatch && initMatch[1]) {
          let equalsMatchPosition = startingLine.lastIndexOf(initMatch[1]);
          column = equalsMatchPosition += initMatch[1].length;
        } else if (startOfLineMatch && startOfLineMatch.index) {
          column = startOfLineMatch.index;
        } else {
          column = 0;
        }

        return Point.fromObject([closeBracketPosition.row, column]);
      }
    } else {
      return null;
    }
  }
   + ' bracket in a char literal', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer("[self fooWithBar:'['] setEnabled:NO]"),
     Point.fromObject([0, 35])
   )).toEqual(Point.fromObject([0, 0]));
 });
 it('inserts an open bracket after an equals sign when initalizing or messaging a class', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('NSObject *foo = NSObject alloc]'),
     Point.fromObject([0, 30])
   )).toEqual(Point.fromObject([0, 16]));
 });
 () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('foo setFoo:@"foo"\nbar:@"bar"\nbaz:@"baz"]'),
     Point.fromObject([2, 10])
   )).toEqual(Point.fromObject([0, 0]));
 }
   + ' with balanced brackets', () => {
   expect(getOpenBracketInsertPosition(
     new TextBuffer('[[NSObject alloc] init]'),
     Point.fromObject([0, 22])
   )).toEqual(null);
 });
Exemple #21
0
// Buffer Point util
// -------------------------
function pointIsAtEndOfLine (editor, point) {
  point = Point.fromObject(point)
  return getEndOfLineForBufferRow(editor, point.row).isEqual(point)
}
   + ' bracket', () => {
   expect(getOpenBracketInsertPosition(new TextBuffer('   ]'), Point.fromObject([0, 3])))
       .toEqual(Point.fromObject([0, 3]));
 });
 spyOn(textEditor, 'bufferPositionForScreenPosition').andCallFake(function() {
   return Point.fromObject(position)
 })
 editor.transact(() => {
   // Temporarily disable autocomplete suggestions.
   this.suggestionsEnabled = false;
   const selectedRange = editor.getSelectedBufferRange();
   const selectionMarker = editor.markBufferRange(selectedRange);
   const selectedText = editor.getSelectedText();
   const selectedLines = selectedText.split('\n');
   const leadingSpaces = new Array(selectedRange.start.column + 1).join(
     ' '
   );
   const placeholder = 'function';
   // Look for start of current top-level.
   let topLevelStart = new Point(0, 0);
   editor.backwardsScanInBufferRange(
     helper.topLevelRegex(),
     [selectedRange.start, topLevelStart],
     ({ range, stop }) => {
       stop();
       topLevelStart = range.start;
     }
   );
   // Look for end of current top-level.
   let topLevelEnd = editor.getEofBufferPosition();
   editor.scanInBufferRange(
     helper.blockRegex(),
     [topLevelStart, editor.getEofBufferPosition()],
     ({ range, stop }) => {
       stop();
       topLevelEnd = range.end;
     }
   );
   const atEndOfFile = topLevelEnd.isEqual(editor.getEofBufferPosition());
   editor.setCursorBufferPosition(topLevelEnd);
   editor.insertText(
     '\n' +
       (atEndOfFile ? '\n' : '') +
       placeholder +
       ' =\n' +
       selectedLines
         .map(text => {
           return helper.tabSpaces() + text.replace(leadingSpaces, '');
         })
         .join('\n') +
       '\n\n'
   );
   editor.setTextInBufferRange(
     selectionMarker.getBufferRange(),
     placeholder
   );
   const cursorPosition1 = new Point(
     topLevelEnd.row +
       1 -
       (selectedLines.length - 1) +
       (atEndOfFile ? 1 : 0),
     0
   );
   editor.setSelectedBufferRanges([
     selectionMarker.getBufferRange(),
     [cursorPosition1, cursorPosition1.translate([0, placeholder.length])],
   ]);
   this.handleEndOfAct(editor);
 });