All files / app/components FileDifferences.tsx

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126                            2x           2x                                                                                                                                                                                                                  
import React from 'react';
import { defer } from 'lodash';
import { style, getStyleVar } from 'app/styles';
import { editor } from 'monaco-editor';
import { debug } from 'app/utilities/logger';
 
export interface FileDifferencesProps {
  rerenderRequestedAt: Date;
  leftFileContents: string;
  rightFileContents: string;
  style?: string | object;
  onFileClick?: (evt, fileName: string) => void;
}
 
const outerStyle = {
  position: 'relative',
  flexGrow: 1,
  overflow: 'hidden',
};
 
const editorStyle = {
  _extends: 'fill',
  position: 'absolute',
};
 
export class FileDifferences extends React.Component<FileDifferencesProps> {
  private monacoEditorElRef = React.createRef<HTMLDivElement>();
  private navigator: any;
 
  constructor(props: FileDifferencesProps) {
    super(props);
    this.renderMonacoEditor = this.renderMonacoEditor.bind(this);
  }
 
  componentDidMount() {
    this.renderMonacoEditor();
    window && window.addEventListener('resize', this.renderMonacoEditor);
  }
 
  componentDidUpdate() {
    defer(() => this.renderMonacoEditor());
  }
 
  render() {
    return (
      <div style={style(outerStyle)}>
        <div style={style(editorStyle)} ref={this.monacoEditorElRef} />
      </div>
    );
  }
 
  renderMonacoEditor() {
    const el = this.monacoEditorElRef.current;
    if (!el) {
      return null;
    }
    el.innerHTML = '';
 
    const leftFileContents =
      (this.props.leftFileContents && atob(this.props.leftFileContents)) || '';
    const rightFileContents =
      (this.props.rightFileContents && atob(this.props.rightFileContents)) ||
      '';
 
    debug(
      `renderMonacoEditor: el ${el.offsetHeight} ${el.clientHeight} ${
        el.offsetWidth
      } ${el.clientWidth}`
    );
    const originalModel = editor.createModel(leftFileContents);
    const modifiedModel = editor.createModel(rightFileContents);
 
    // @ts-ignore
    editor.defineTheme('myTheme', this.getTheme());
    editor.setTheme('myTheme');
 
    const diffEditor = editor.createDiffEditor(el, { readOnly: true });
    diffEditor.setModel({
      original: originalModel,
      modified: modifiedModel,
    });
 
    this.navigator = editor.createDiffNavigator(diffEditor, {
      followsCaret: true, // resets the navigator state when the user selects something in the editor
      ignoreCharChanges: true, // jump from line to line
    });
  }
 
  getTheme() {
    const background = this.getColorValue('background');
    const foreground = this.getColorValue('text');
    const theme = {
      base: 'vs',
      inherit: true,
      rules: [{ background, foreground }],
      colors: {
        'editor.foreground': foreground,
        'editor.background': background,
        // don't show selection
        'editorCursor.foreground': background,
        // 'editor.lineHighlightBackground': '#0000FF20',
        // 'editorLineNumber.foreground': '#008800',
        // 'editor.selectionBackground': '#88000030',
        // 'editor.inactiveSelectionBackground': '#88000015',
      },
    };
    debug('FileDifferences.getTheme() returning ', theme);
    return theme;
  }
 
  getColorValue(ourName: string): string {
    const valueIn = getStyleVar('colors', ourName);
 
    // interpolate css variable values to real color value for monaco
    const matches = valueIn.match(/var\(([^\)]*)/);
    if (matches) {
      const varName = matches[1];
      const value = getComputedStyle(document.documentElement).getPropertyValue(
        varName
      );
      return value;
    }
    return valueIn;
  }
}