Esempio n. 1
0
        ).flatMap(textEditor => {
          const buffer = textEditor.getBuffer();
          if (buffers.has(buffer)) {
            return Observable.empty();
          }
          buffers.add(buffer);

          const bufferPath = nullthrows(buffer.getPath());

          const bufferReloads = observableFromSubscribeFunction(
            buffer.onDidReload.bind(buffer),
          );
          const bufferChanges = observableFromSubscribeFunction(
            buffer.onDidChangeText.bind(buffer),
          );

          // TODO (tjfryan): handle renames `onDidChangePath`

          // This is in a flatMap, so we need to make sure this terminates
          // We can terminate, `takeUntil`, buffer is destroyed
          // And make sure to clear the cached diff for the buffer once we no
          // longer care about it
          const bufferDestroyed = observableFromSubscribeFunction(
            buffer.onDidDestroy.bind(buffer),
          ).do(() => {
            buffers.delete(buffer);
            repository.deleteDiffInfo(bufferPath);
            fileContentsAtHead.delete(bufferPath);
          });

          // recalculate on bufferReload, bufferChanges, and when we get
          // this file's data from hg cat
          return Observable.merge(
            bufferReloads,
            bufferChanges,
            fetchFileContentsAtHead.filter(fileContentsList =>
              fileContentsList.some(
                fileInfo =>
                  nuclideUri.join(
                    repository.getWorkingDirectory(),
                    fileInfo.abspath,
                  ) === bufferPath,
              ),
            ),
          )
            .let(fastDebounce(200))
            .switchMap(() => {
              const oldContents = fileContentsAtHead.get(bufferPath);
              if (oldContents == null) {
                return Observable.empty();
              }
              const newContents = buffer.getText();
              return gitDiffStrings(oldContents, newContents)
                .map(diffOutput => parseHgDiffUnifiedOutput(diffOutput))
                .do(diffInfo => {
                  repository.setDiffInfo(bufferPath, diffInfo);
                });
            })
            .takeUntil(bufferDestroyed);
        });
Esempio n. 2
0
 /**
  * A stream of all signatures from an editor.
  */
 _getSignatureStream(editor: atom$TextEditor): Observable<?SignatureHelp> {
   return Observable.concat(
     // Start with a null signature to clear out any prior signatures.
     Observable.of(null),
     // Immediately start fetching signatures for the current position.
     Observable.concat(
       Observable.defer(() => Observable.of(editor.getCursorBufferPosition())),
       // Further cursor changes will be debounced.
       getCursorPositions(editor).let(fastDebounce(CURSOR_DEBOUNCE_TIME)),
     )
       .distinctUntilChanged((a, b) => a.isEqual(b))
       .switchMap(point => this._getSignatures(editor, point))
       // Stop once we get a null result.
       .takeWhile(Boolean)
       // Stop once the escape key is pressed.
       // NOTE: we can't use core:cancel because plugins like vim-mode-plus override it.
       .takeUntil(
         Observable.fromEvent(editor.getElement(), 'keydown').filter(
           (evt: KeyboardEvent) => evt.keyCode === 27,
         ),
       ),
     // Terminate with a null signature to clear any visible signatures.
     Observable.of(null),
   );
 }
Esempio n. 3
0
 /**
  * A stream of all signature help triggers.
  */
 _signatureHelpTriggers(editor: atom$TextEditor): Observable<mixed> {
   return Observable.merge(
     // 1) Any keypresses that match a triggerCharacter.
     observableFromSubscribeFunction(cb =>
       editor.getBuffer().onDidChangeText(cb),
     )
       // The change events and cursor changes are often sequential.
       // We need to make sure we use the final cursor position.
       .let(fastDebounce(0))
       .filter(edit => {
         if (edit.changes.length !== 1) {
           return false;
         }
         const change = edit.changes[0];
         // Use the start of the current selection as the cursor position.
         // (Autocomplete often inserts a placeholder and puts the cursor at the end.)
         const cursorPosition = editor.getSelectedBufferRange().start;
         if (
           change.newText.length === 0 ||
           // Don't allow multi-line changes.
           change.newRange.start.row !== change.newRange.end.row ||
           // The change should cover the current cursor position.
           !change.newRange.containsPoint(cursorPosition)
         ) {
           return false;
         }
         // Use the character before the cursor as the 'trigger character'.
         const index = Math.max(
           0,
           cursorPosition.column - change.newRange.start.column - 1,
         );
         for (const provider of this._providerRegistry.getAllProvidersForEditor(
           editor,
         )) {
           if (provider.triggerCharacters != null) {
             if (provider.triggerCharacters.has(change.newText[index])) {
               return true;
             }
           }
         }
         return false;
       }),
     // 2) Explicit usage of the Atom command.
     this._commands.filter(e => e === editor),
   );
 }
Esempio n. 4
0
  /**
   * An observable of the state that's shared between all panel copies. State that's unique to a
   * single copy of the diagnostics panel is managed in DiagnosticsViewModel. Generally, users will
   * only have one copy of the diagnostics panel so this is mostly a theoretical distinction,
   * however, each copy should have its own sorting, filtering, etc.
   */
  _getGlobalViewStates(): Observable<GlobalViewState> {
    if (this._globalViewStates == null) {
      const packageStates = this._model.toObservable();
      const updaters = packageStates
        .map(state => state.diagnosticUpdater)
        .distinctUntilChanged();

      const diagnosticsStream = updaters
        .switchMap(
          updater =>
            updater == null
              ? Observable.of([])
              : observableFromSubscribeFunction(updater.observeMessages),
        )
        .map(diagnostics => diagnostics.filter(d => d.type !== 'Hint'))
        .let(fastDebounce(100))
        .startWith([]);

      const showTracesStream: Observable<
        boolean,
      > = (featureConfig.observeAsStream(SHOW_TRACES_SETTING): any);
      const setShowTraces = showTraces => {
        featureConfig.set(SHOW_TRACES_SETTING, showTraces);
      };

      const showDirectoryColumnStream: Observable<
        boolean,
      > = (featureConfig.observeAsStream(
        'atom-ide-diagnostics-ui.showDirectoryColumn',
      ): any);

      const autoVisibilityStream: Observable<
        boolean,
      > = (featureConfig.observeAsStream(
        'atom-ide-diagnostics-ui.autoVisibility',
      ): any);

      const pathToActiveTextEditorStream = getActiveEditorPaths();

      const filterByActiveTextEditorStream = packageStates
        .map(state => state.filterByActiveTextEditor)
        .distinctUntilChanged();
      const setFilterByActiveTextEditor = filterByActiveTextEditor => {
        this._model.setState({filterByActiveTextEditor});
      };

      const supportedMessageKindsStream = updaters
        .switchMap(
          updater =>
            updater == null
              ? Observable.of(new Set(['lint']))
              : observableFromSubscribeFunction(
                  updater.observeSupportedMessageKinds.bind(updater),
                ),
        )
        .distinctUntilChanged(areSetsEqual);

      const uiConfigStream = updaters.switchMap(
        updater =>
          updater == null
            ? Observable.of([])
            : observableFromSubscribeFunction(
                updater.observeUiConfig.bind(updater),
              ),
      );

      this._globalViewStates = Observable.combineLatest(
        diagnosticsStream,
        filterByActiveTextEditorStream,
        pathToActiveTextEditorStream,
        showTracesStream,
        showDirectoryColumnStream,
        autoVisibilityStream,
        supportedMessageKindsStream,
        uiConfigStream,
        // $FlowFixMe
        (
          diagnostics,
          filterByActiveTextEditor,
          pathToActiveTextEditor,
          showTraces,
          showDirectoryColumn,
          autoVisibility,
          supportedMessageKinds,
          uiConfig,
        ) => ({
          diagnostics,
          filterByActiveTextEditor,
          pathToActiveTextEditor,
          showTraces,
          showDirectoryColumn,
          autoVisibility,
          onShowTracesChange: setShowTraces,
          onFilterByActiveTextEditorChange: setFilterByActiveTextEditor,
          supportedMessageKinds,
          uiConfig,
        }),
      );
    }
    return this._globalViewStates;
  }