From 90b490c28b97a91af428029bc44917eab6ab0166 Mon Sep 17 00:00:00 2001 From: Dick Choi Date: Mon, 3 Oct 2016 22:28:13 +0900 Subject: [PATCH] use codemirror --- browser/components/CodeEditor.js | 235 ++--- browser/components/MarkdownEditor.js | 4 +- browser/components/MarkdownPreview.js | 1 - browser/finder/NoteDetail.js | 27 +- browser/finder/index.js | 2 +- browser/finder/ipcClient.js | 12 + browser/lib/consts.js | 16 +- browser/lib/modes.js | 868 ------------------ browser/main/Detail/SnippetNoteDetail.js | 40 +- browser/main/global.styl | 13 + browser/main/lib/ConfigManager.js | 29 +- .../main/lib/dataApi/resolveStorageNotes.js | 13 +- .../main/modals/PreferencesModal/ConfigTab.js | 8 +- lib/finder.html | 8 +- lib/main.html | 11 +- package.json | 8 +- webpack-skeleton.js | 1 + 17 files changed, 217 insertions(+), 1079 deletions(-) delete mode 100644 browser/lib/modes.js diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 14631e73..fb5b6646 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -1,183 +1,107 @@ import React, { PropTypes } from 'react' -import ReactDOM from 'react-dom' -import modes from '../lib/modes' import _ from 'lodash' +import CodeMirror from 'codemirror' -const ace = window.ace +CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js' const defaultEditorFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace'] +function pass (name) { + switch (name) { + case 'ejs': + return 'Embedded Javascript' + case 'html_ruby': + return 'Embedded Ruby' + case 'objectivec': + return 'Objective C' + case 'text': + return 'Plain Text' + default: + return name + } +} + export default class CodeEditor extends React.Component { constructor (props) { super(props) this.changeHandler = (e) => this.handleChange(e) - this.blurHandler = (e) => { - e.stopPropagation() + this.blurHandler = (editor, e) => { + if (e == null) return null let el = e.relatedTarget - let isStillFocused = false while (el != null) { if (el === this.refs.root) { - isStillFocused = true - break + return } el = el.parentNode } - - if (!isStillFocused && this.props.onBlur != null) this.props.onBlur(e) + this.props.onBlur != null && this.props.onBlur(e) } - - this.killedBuffer = '' - this.execHandler = (e) => { - console.info('ACE COMMAND >> %s', e.command.name) - switch (e.command.name) { - case 'gotolinestart': - e.preventDefault() - { - let position = this.editor.getCursorPosition() - this.editor.navigateTo(position.row, 0) - } - break - case 'gotolineend': - e.preventDefault() - let position = this.editor.getCursorPosition() - this.editor.navigateTo(position.row, this.editor.getSession().getLine(position.row).length) - break - case 'jumptomatching': - e.preventDefault() - this.editor.navigateUp() - break - case 'removetolineend': - e.preventDefault() - let range = this.editor.getSelectionRange() - let session = this.editor.getSession() - if (range.isEmpty()) { - range.setEnd(range.start.row, session.getLine(range.start.row).length) - this.killedBuffer = session.getTextRange(range) - if (this.killedBuffer.length > 0) { - console.log('remove to lineend') - session.remove(range) - } else { - if (session.getLength() === range.start.row) { - return - } - range.setStart(range.start.row, range.end.col) - range.setEnd(range.start.row + 1, 0) - this.killedBuffer = '\n' - session.remove(range) - } - } else { - this.killedBuffer = session.getTextRange(range) - session.remove(range) - } - } - } - this.afterExecHandler = (e) => { - switch (e.command.name) { - case 'find': - Array.prototype.forEach.call(ReactDOM.findDOMNode(this).querySelectorAll('.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close'), (el) => { - el.removeEventListener('blur', this.blurHandler) - el.addEventListener('blur', this.blurHandler) - }) - break - } - } - - this.state = { - } - - this.silentChange = false } componentWillReceiveProps (nextProps) { - if (nextProps.readOnly !== this.props.readOnly) { - this.editor.setReadOnly(!!nextProps.readOnly) - } + // if (nextProps.readOnly !== this.props.readOnly) { + // this.editor.setReadOnly(!!nextProps.readOnly) + // } } componentDidMount () { - let { mode, value, theme, fontSize } = this.props - this.value = value - let el = ReactDOM.findDOMNode(this) - let editor = this.editor = ace.edit(el) - editor.$blockScrolling = Infinity - editor.renderer.setShowGutter(true) - editor.setTheme('ace/theme/' + theme) - editor.moveCursorTo(0, 0) - editor.setReadOnly(!!this.props.readOnly) - editor.setFontSize(fontSize) - - editor.on('blur', this.blurHandler) - - editor.commands.addCommand({ - name: 'Emacs cursor up', - bindKey: {mac: 'Ctrl-P'}, - exec: function (editor) { - editor.navigateUp(1) - if (editor.getCursorPosition().row < editor.getFirstVisibleRow()) editor.scrollToLine(editor.getCursorPosition().row, false, false) - }, - readOnly: true - }) - editor.commands.addCommand({ - name: 'Emacs kill buffer', - bindKey: {mac: 'Ctrl-Y'}, - exec: function (editor) { - editor.insert(this.killedBuffer) - }.bind(this), - readOnly: true + this.editor = CodeMirror(this.refs.root, { + value: this.props.value, + lineNumbers: true, + lineWrapping: true, + theme: this.props.theme }) + this.setMode(this.props.mode) + this.editor.on('blur', this.blurHandler) + this.editor.on('change', this.changeHandler) + // editor.setTheme('ace/theme/' + theme) + // editor.setReadOnly(!!this.props.readOnly) - editor.commands.on('exec', this.execHandler) - editor.commands.on('afterExec', this.afterExecHandler) - - var session = editor.getSession() - mode = _.find(modes, {name: mode}) - let syntaxMode = mode != null - ? mode.mode - : 'text' - session.setMode('ace/mode/' + syntaxMode) - - session.setUseSoftTabs(this.props.indentType === 'space') - session.setTabSize(this.props.indentSize) - session.setOption('useWorker', true) - session.setUseWrapMode(true) - session.setValue(_.isString(value) ? value : '') - - session.on('change', this.changeHandler) + // this.editor.setTabSize(this.props.indentSize) + // this.editor.setTabSize(this.props.indentSize) + // session.setUseSoftTabs(this.props.indentType === 'space') + // session.setTabSize(this.props.indentSize) + // session.setUseWrapMode(true) } componentWillUnmount () { - this.editor.getSession().removeListener('change', this.changeHandler) - this.editor.removeListener('blur', this.blurHandler) - this.editor.commands.removeListener('exec', this.execHandler) - this.editor.commands.removeListener('afterExec', this.afterExecHandler) + this.editor.off('blur', this.blurHandler) + this.editor.off('change', this.changeHandler) } componentDidUpdate (prevProps, prevState) { - let { value } = this.props - this.value = value - let editor = this.editor - let session = this.editor.getSession() - + let needRefresh = false if (prevProps.mode !== this.props.mode) { - let mode = _.find(modes, {name: this.props.mode}) - let syntaxMode = mode != null - ? mode.mode - : 'text' - session.setMode('ace/mode/' + syntaxMode) + this.setMode(this.props.mode) } if (prevProps.theme !== this.props.theme) { - editor.setTheme('ace/theme/' + this.props.theme) + this.editor.setOption('theme', this.props.theme) + needRefresh = true } if (prevProps.fontSize !== this.props.fontSize) { - editor.setFontSize(this.props.fontSize) + needRefresh = true } - if (prevProps.indentSize !== this.props.indentSize) { - session.setTabSize(this.props.indentSize) + if (prevProps.fontFamily !== this.props.fontFamily) { + needRefresh = true } - if (prevProps.indentType !== this.props.indentType) { - session.setUseSoftTabs(this.props.indentType === 'space') + + if (needRefresh) { + this.editor.refresh() } + // if (prevProps.indentSize !== this.props.indentSize) { + // session.setTabSize(this.props.indentSize) + // } + // if (prevProps.indentType !== this.props.indentType) { + // session.setUseSoftTabs(this.props.indentType === 'space') + // } + } + + setMode (mode) { + let syntax = CodeMirror.findModeByName(pass(mode)) + if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') + this.editor.setOption('mode', syntax.mode) + CodeMirror.autoLoadMode(this.editor, syntax.mode) } handleChange (e) { @@ -187,20 +111,10 @@ export default class CodeEditor extends React.Component { } } - getFirstVisibleRow () { - return this.editor.getFirstVisibleRow() - } - - getCursorPosition () { - return this.editor.getCursorPosition() - } - moveCursorTo (row, col) { - this.editor.moveCursorTo(row, col) } scrollToLine (num) { - this.editor.scrollToLine(num, false, false) } focus () { @@ -212,21 +126,21 @@ export default class CodeEditor extends React.Component { } reload () { - let session = this.editor.getSession() - session.removeListener('change', this.changeHandler) - session.setValue(this.props.value) - session.getUndoManager().reset() - session.on('change', this.changeHandler) + // Change event shouldn't be fired when switch note + this.editor.off('change', this.changeHandler) + this.editor.setValue(this.props.value) + this.editor.clearHistory() + this.editor.on('change', this.changeHandler) } setValue (value) { - let session = this.editor.getSession() - session.setValue(value) - this.value = value + let cursor = this.editor.getCursor() + this.editor.setValue(value) + this.editor.setCursor(cursor) } render () { - let { className, fontFamily } = this.props + let { className, fontFamily, fontSize } = this.props fontFamily = _.isString(fontFamily) && fontFamily.length > 0 ? [fontFamily].concat(defaultEditorFontFamily) : defaultEditorFontFamily @@ -239,7 +153,8 @@ export default class CodeEditor extends React.Component { ref='root' tabIndex='-1' style={{ - fontFamily: fontFamily.join(', ') + fontFamily: fontFamily.join(', '), + fontSize: fontSize }} /> ) diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index c3c46890..ad35354b 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -48,12 +48,12 @@ class MarkdownEditor extends React.Component { handleBlur (e) { let { config } = this.props if (config.editor.switchPreview === 'BLUR') { - let cursorPosition = this.refs.code.getCursorPosition() + let cursorPosition = this.refs.code.editor.getCursor() this.setState({ status: 'PREVIEW' }, () => { this.refs.preview.focus() - this.refs.preview.scrollTo(cursorPosition.row) + this.refs.preview.scrollTo(cursorPosition.line) }) } } diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 9c38ce64..b052c765 100644 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -192,7 +192,6 @@ MarkdownPreview.propTypes = { onDoubleClick: PropTypes.func, onMouseUp: PropTypes.func, onMouseDown: PropTypes.func, - onMouseMove: PropTypes.func, className: PropTypes.string, value: PropTypes.string } diff --git a/browser/finder/NoteDetail.js b/browser/finder/NoteDetail.js index 3652017c..9d4ce907 100644 --- a/browser/finder/NoteDetail.js +++ b/browser/finder/NoteDetail.js @@ -4,12 +4,26 @@ import styles from './NoteDetail.styl' import MarkdownPreview from 'browser/components/MarkdownPreview' import MarkdownEditor from 'browser/components/MarkdownEditor' import CodeEditor from 'browser/components/CodeEditor' -import modes from 'browser/lib/modes' +import CodeMirror from 'codemirror' const electron = require('electron') const { clipboard } = electron const path = require('path') +function pass (name) { + switch (name) { + case 'ejs': + return 'Embedded Javascript' + case 'html_ruby': + return 'Embedded Ruby' + case 'objectivec': + return 'Objective C' + case 'text': + return 'Plain Text' + default: + return name + } +} function notify (title, options) { if (global.process.platform === 'win32') { options.icon = path.join('file://', global.__dirname, '../../resources/app.png') @@ -118,9 +132,9 @@ class NoteDetail extends React.Component { let viewList = note.snippets.map((snippet, index) => { let isActive = this.state.snippetIndex === index - let mode = snippet.mode === 'text' - ? null - : modes.filter((mode) => mode.name === snippet.mode)[0] + + let syntax = CodeMirror.findModeByName(pass(snippet.mode)) + if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') return
{snippet.mode === 'markdown' diff --git a/browser/finder/index.js b/browser/finder/index.js index c8161b84..c9f0bc04 100644 --- a/browser/finder/index.js +++ b/browser/finder/index.js @@ -9,7 +9,7 @@ import styles from './FinderMain.styl' import StorageSection from './StorageSection' import NoteList from './NoteList' import NoteDetail from './NoteDetail' - +require('!!style!css!stylus?sourceMap!../main/global.styl') const electron = require('electron') const { remote } = electron const { Menu } = remote diff --git a/browser/finder/ipcClient.js b/browser/finder/ipcClient.js index e9804258..9067aa8d 100644 --- a/browser/finder/ipcClient.js +++ b/browser/finder/ipcClient.js @@ -86,6 +86,18 @@ nodeIpc.connectTo( } else { document.body.setAttribute('data-theme', 'default') } + + let editorTheme = document.getElementById('editorTheme') + if (editorTheme == null) { + editorTheme = document.createElement('link') + editorTheme.setAttribute('id', 'editorTheme') + editorTheme.setAttribute('rel', 'stylesheet') + document.head.appendChild(editorTheme) + } + if (config.editor.theme !== 'default') { + editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css') + } + store.default.dispatch({ type: 'SET_CONFIG', config: config diff --git a/browser/lib/consts.js b/browser/lib/consts.js index 0ebec02a..4241e2db 100644 --- a/browser/lib/consts.js +++ b/browser/lib/consts.js @@ -1,3 +1,16 @@ +const path = require('path') +const fs = require('sander') +const { remote } = require('electron') +const { app } = remote + +const themePath = process.env.NODE_ENV === 'production' + ? path.join(app.getAppPath(), './node_modules/codemirror/theme') + : require('path').resolve('./node_modules/codemirror/theme') +const themes = fs.readdirSync(themePath) + .map((themePath) => { + return themePath.substring(0, themePath.lastIndexOf('.')) + }) + const consts = { FOLDER_COLORS: [ '#E10051', @@ -16,7 +29,8 @@ const consts = { 'Turquoise', 'Dodger Blue', 'Violet Eggplant' - ] + ], + THEMES: themes } module.exports = consts diff --git a/browser/lib/modes.js b/browser/lib/modes.js deleted file mode 100644 index 8f1cdbd5..00000000 --- a/browser/lib/modes.js +++ /dev/null @@ -1,868 +0,0 @@ -const modes = [ - { - name: 'text', - label: 'Plain text', - mode: 'text' - }, - { - name: 'abap', - label: 'ABAP', - alias: [], - mode: 'abap', - match: /\.abap$/i - }, - { - name: 'abc', - label: 'ABC', - alias: [], - mode: 'abc', - match: /\.abc$/i - }, - { - name: 'actionscript', - label: 'ActionScript', - alias: ['as'], - mode: 'actionscript', - match: /\.as$/i - }, - { - name: 'ada', - label: 'Ada', - alias: [], - mode: 'ada', - match: /\.ada$/i - }, - { - name: 'apache_conf', - label: 'Apache config', - alias: ['apache', 'conf'], - mode: 'apache_conf', - match: /\.conf$/i - }, - { - name: 'applescript', - label: 'AppleScript', - alias: ['scpt'], - mode: 'applescript', - match: /\.scpt$|\.scptd$|\.AppleScript$/i - }, - { - name: 'asciidoc', - label: 'AsciiDoc', - alias: ['ascii', 'doc', 'txt'], - mode: 'asciidoc', - match: /\.txt$/i - }, - { - name: 'assembly_x86', - label: 'Assembly x86', - alias: ['assembly', 'x86', 'asm'], - mode: 'assembly_x86', - match: /\.asm$/i - }, - { - name: 'autohotkey', - label: 'AutoHotkey', - alias: ['ahk'], - mode: 'autohotkey', - match: /\.ahk$/i - }, - { - name: 'batchfile', - label: 'Batch file', - alias: ['dos', 'windows', 'bat', 'cmd', 'btm'], - mode: 'batchfile', - match: /\.bat$|\.cmd$/i - }, - { - name: 'c', - label: 'C', - alias: ['c', 'h', 'clang', 'clang'], - mode: 'c_cpp', - match: /\.c$|\.h\+\+$/i - }, - { - name: 'cirru', - label: 'Cirru', - alias: [], - mode: 'cirru', - match: /\.cirru$/i - }, - { - name: 'clojure', - label: 'Clojure', - alias: ['clj', 'cljs', 'cljc', 'edn'], - mode: 'clojure', - match: /\.clj$|\.cljs$|\.cljc$|\.edn$/i - }, - { - name: 'cobol', - label: 'COBOL', - alias: ['cbl', 'cob', 'cpy'], - mode: 'cobol', - match: /\.cbl$|\.cob$\.cpy$/i - }, - { - name: 'coffee', - label: 'CoffeeScript', - alias: ['coffee'], - mode: 'coffee', - match: /\.coffee$|\.litcoffee$/i - }, - { - name: 'coldfusion', - label: 'ColdFusion', - alias: ['cfm', 'cfc'], - mode: 'coldfusion', - match: /\.cfm$|\.cfc$/i - }, - { - name: 'cpp', - label: 'C++', - alias: ['cc', 'cpp', 'cxx', 'hh', 'c++', 'cplusplus'], - mode: 'c_cpp', - match: /\.cc$|\.cpp$|\.cxx$|\.C$|\.c\+\+$|\.hh$|\.hpp$|\.hxx$|\.h\+\+$/i - }, - { - name: 'csharp', - label: 'C#', - alias: ['cs', 'c#'], - mode: 'csharp', - match: /\.cs$/i - }, - { - name: 'css', - label: 'CSS', - alias: ['cascade', 'stylesheet'], - mode: 'css', - match: /\.css$/i - }, - { - name: 'curly', - label: 'Curly', - alias: [], - mode: 'curly', - match: /\.curly$/i - }, - { - name: 'd', - label: 'D', - alias: ['dlang'], - mode: 'd', - match: /\.d$/i - }, - { - name: 'dockerfile', - label: 'DockerFile', - alias: ['docker'], - mode: 'docker', - match: /Dockerfile$/i - }, - { - name: 'dart', - label: 'Dart', - alias: [], - mode: 'dart', - match: /\.dart$/i - }, - { - name: 'diff', - label: 'Diff', - alias: [], - mode: 'diff', - match: /\.diff$|\.patch$/i - }, - { - name: 'django', - label: 'Django', - alias: [], - mode: 'djt', - match: /\.djt$/i - }, - { - name: 'dot', - label: 'DOT', - alias: ['gv'], - mode: 'dot', - match: /\.gv$|\.dot/i - }, - { - name: 'eiffel', - label: 'Eiffel', - alias: [], - mode: 'eiffel', - match: /\.e$/i - }, - { - name: 'ejs', - label: 'EJS', - alias: [], - mode: 'ejs', - match: /\.ejs$/i - }, - { - name: 'elixir', - label: 'Elixir', - alias: ['ex', 'exs'], - mode: 'elixir', - match: /\.ex$|\.exs$/i - }, - { - name: 'elm', - label: 'Elm', - alias: [], - mode: 'elm', - match: /\.elm$/i - }, - { - name: 'erlang', - label: 'Erlang', - alias: ['erl', 'hrl'], - mode: 'erlang', - match: /\.erl$|\.hrl$/i - }, - { - name: 'forth', - label: 'Forth', - alias: ['fs', 'fth'], - mode: 'forth', - match: /\.fs$|\.fth$/i - }, - { - name: 'freemaker', - label: 'Freemaker', - alias: ['ftl'], - mode: 'ftl', - match: /\.ftl$/i - }, - { - name: 'gcode', - label: 'G-code', - alias: ['mpt', 'mpf', 'nc'], - mode: 'gcode', - match: /\.mpt$|\.mpf$|\.nc$/i - }, - { - name: 'gherkin', - label: 'Gherkin', - alias: ['cucumber'], - mode: 'gherkin', - match: /\.feature$/i - }, - { - name: 'gitignore', - label: 'Gitignore', - alias: ['git'], - mode: 'gitignore', - match: /\.gitignore$/i - }, - { - name: 'glsl', - label: 'GLSL', - alias: ['opengl', 'shading'], - mode: 'glsl', - match: /\.vert$|\.frag/i - }, - { - name: 'golang', - label: 'Go', - alias: ['go'], - mode: 'golang', - match: /\.go$/i - }, - { - name: 'groovy', - label: 'Groovy', - alias: [], - mode: 'grooby', - match: /\.groovy$/i - }, - { - name: 'haml', - label: 'Haml', - alias: [], - mode: 'haml', - match: /\.haml$/i - }, - { - name: 'handlebars', - label: 'Handlebars', - alias: ['hbs'], - mode: 'handlebars', - match: /\.hbs$/i - }, - { - name: 'haskell', - label: 'Haskell', - alias: ['hs', 'lhs'], - mode: 'haskell', - match: /\.hs$|\.lhs$/i - }, - { - name: 'haxe', - label: 'Haxe', - alias: ['hx', 'hxml'], - mode: 'haxe', - match: /\.hx$|\.hxml$/i - }, - { - name: 'html', - label: 'HTML', - alias: [], - mode: 'html', - match: /\.html$/i - }, - { - name: 'html_ruby', - label: 'HTML (Ruby)', - alias: ['erb', 'rhtml'], - mode: 'html_ruby', - match: /\.erb$|\.rhtml$/i - }, - { - name: 'jsx', - label: 'JSX', - alias: ['es', 'babel', 'js', 'jsx', 'react'], - mode: 'jsx', - match: /\.jsx$/i - }, - { - name: 'typescript', - label: 'TypeScript', - alias: ['ts'], - mode: 'typescript', - match: /\.ts$/i - }, - { - name: 'ini', - label: 'INI file', - alias: [], - mode: 'ini', - match: /\.ini$/i - }, - { - name: 'io', - label: 'Io', - alias: [], - mode: 'io', - match: /\.io$/i - }, - { - name: 'jack', - label: 'Jack', - alias: [], - mode: 'jack', - match: /\.jack$/i - }, - { - name: 'pug', - label: 'Pug(Jade)', - alias: ['jade'], - mode: 'jade', - match: /\.jade$|\.pug$/i - }, - { - name: 'java', - label: 'Java', - alias: [], - mode: 'java', - match: /\.java$/i - }, - { - name: 'javascript', - label: 'JavaScript', - alias: ['js', 'jscript', 'babel', 'es'], - mode: 'javascript', - match: /\.js$/i - }, - { - name: 'json', - label: 'JSON', - alias: [], - mode: 'json', - match: /\.json$/i - }, - { - name: 'jsoniq', - label: 'JSONiq', - alias: ['query'], - mode: 'jsoniq', - match: /\.jq$|\.jqy$/i - }, - { - name: 'jsp', - label: 'JSP', - alias: [], - mode: 'jsp', - match: /\.jsp$/i - }, - { - name: 'julia', - label: 'Julia', - alias: [], - mode: 'julia', - match: /\.jl$/i - }, - { - name: 'latex', - label: 'Latex', - alias: ['tex'], - mode: 'latex', - match: /\.tex$/i - }, - { - name: 'lean', - label: 'Lean', - alias: [], - mode: 'lean', - match: /\.lean$/i - }, - { - name: 'less', - label: 'Less', - alias: [], - mode: 'less', - match: /\.less$/i - }, - { - name: 'liquid', - label: 'Liquid', - alias: [], - mode: 'liquid', - match: /\.liquid$/i - }, - { - name: 'lisp', - label: 'Lisp', - alias: ['lsp'], - mode: 'lisp', - match: /\.lisp$|\.lsp$|\.cl/i - }, - { - name: 'livescript', - label: 'LiveScript', - alias: ['ls'], - mode: 'livescript', - match: /\.ls$/i - }, - { - name: 'logiql', - label: 'LogiQL', - alias: [], - mode: 'logiql' - }, - { - name: 'lsl', - label: 'LSL', - alias: [], - mode: 'lsl', - match: /\.lsl$/i - }, - { - name: 'lua', - label: 'Lua', - alias: [], - mode: 'lua', - match: /\.lsl$/i - }, - { - name: 'luapage', - label: 'Luapage', - alias: [], - mode: 'luapage', - match: /\.lp$/i - }, - { - name: 'lucene', - label: 'Lucene', - alias: [], - mode: 'lucene' - }, - { - name: 'makefile', - label: 'Makefile', - alias: [], - mode: 'makefile', - match: /Makefile$/i - }, - { - name: 'markdown', - label: 'Markdown', - alias: ['md'], - mode: 'markdown', - match: /\.md$/i - }, - { - name: 'mask', - label: 'Mask', - alias: [], - mode: 'mask' - }, - { - name: 'matlab', - label: 'MATLAB', - alias: [], - mode: 'matlab', - match: /\.m$|\.mat$/i - }, - { - name: 'maze', - label: 'Maze', - alias: [], - mode: 'maze' - }, - { - name: 'mel', - label: 'MEL', - alias: [], - mode: 'mel' - }, - { - name: 'mipsassembler', - label: 'MIPS assembly', - alias: [], - mode: 'mipsassembler' - }, - { - name: 'mushcode', - label: 'MUSHCode', - alias: [], - mode: 'mushcode' - }, - { - name: 'mysql', - label: 'MySQL', - alias: [], - mode: 'mysql', - match: /\.mysql$/i - }, - { - name: 'nix', - label: 'Nix', - alias: [], - mode: 'nix', - match: /\.nix$/i - }, - { - name: 'objectivec', - label: 'Objective C', - alias: ['objc'], - mode: 'objectivec', - match: /\.h$|\.m$|\.mm$/i - }, - { - name: 'ocaml', - label: 'OCaml', - alias: [], - mode: 'ocaml', - match: /\.ml$|\.mli$/i - }, - { - name: 'pascal', - label: 'Pascal', - alias: [], - mode: 'pascal', - match: /\.pp$|\.pas$|\.inc$/i - }, - { - name: 'perl', - label: 'Perl', - alias: [], - mode: 'perl', - match: /\.pl$|\.pm$|\.t$|\.pod$/i - }, - { - name: 'pgsql', - label: 'Postgres SQL', - alias: ['postgres'], - mode: 'pgsql', - match: /\.pgsql$/i - }, - { - name: 'php', - label: 'PHP', - alias: [], - mode: 'php', - match: /\.php$/i - }, - { - name: 'powershell', - label: 'PowerShell', - alias: ['ps1'], - mode: 'powershell', - match: /\.ps1$/i - }, - { - name: 'praat', - label: 'Praat', - alias: [], - mode: 'praat' - }, - { - name: 'prolog', - label: 'Prolog', - alias: ['pl', 'pro'], - mode: 'prolog', - match: /\.pl$/i - }, - { - name: 'properties', - label: 'Properties', - alias: [], - mode: 'properties', - match: /\.properties$/i - }, - { - name: 'protobuf', - label: 'Protocol Buffers', - alias: ['protocol', 'buffers'], - mode: 'protobuf', - match: /\.proto$/i - }, - { - name: 'python', - label: 'Python', - alias: ['py'], - mode: 'python', - match: /\.py$/i - }, - { - name: 'r', - label: 'R', - alias: ['rlang'], - mode: 'r', - match: /\.r$/i - }, - { - name: 'rdoc', - label: 'RDoc', - alias: [], - mode: 'rdoc', - match: /\.rdoc$/i - }, - { - name: 'ruby', - label: 'Ruby', - alias: ['rb'], - mode: 'ruby', - match: /\.rb$/i - }, - { - name: 'rust', - label: 'Rust', - alias: [], - mode: 'rust', - match: /\.rs$/i - }, - { - name: 'sass', - label: 'Sass', - alias: [], - mode: 'sass', - match: /\.sass$/i - }, - { - name: 'scad', - label: 'SCAD', - alias: [], - mode: 'scad', - match: /\.scad$/i - }, - { - name: 'scala', - label: 'Scala', - alias: [], - mode: 'scala', - match: /\.scala$|\.sc$/i - }, - { - name: 'scheme', - label: 'Scheme', - alias: ['scm', 'ss'], - mode: 'scheme', - match: /\.scm$|\.ss$/i - }, - { - name: 'scss', - label: 'Scss', - alias: [], - mode: 'scss', - match: /\.scss$/i - }, - { - name: 'sh', - label: 'Shell', - alias: ['shell'], - mode: 'sh', - match: /\.sh$/i - }, - { - name: 'sjs', - label: 'StratifiedJS', - alias: ['stratified'], - mode: 'sjs', - match: /\.sjs$/i - }, - { - name: 'smarty', - label: 'Smarty', - alias: [], - mode: 'smarty', - match: /\.smarty$/i - }, - { - name: 'snippets', - label: 'Snippets', - alias: [], - mode: 'snippets', - match: /snippets$/i - }, - { - name: 'soy_template', - label: 'Soy Template', - alias: ['soy'], - mode: 'soy_template', - match: /\.soy$/i - }, - { - name: 'space', - label: 'Space', - alias: [], - mode: 'space', - match: /\.space$/i - }, - { - name: 'sql', - label: 'SQL', - alias: [], - mode: 'sql', - match: /\.sql$/i - }, - { - name: 'sqlserver', - label: 'SQL Server', - alias: [], - mode: 'sqlserver' - }, - { - name: 'stylus', - label: 'Stylus', - alias: [], - mode: 'stylus', - match: /\.styl$/i - }, - { - name: 'svg', - label: 'SVG', - alias: [], - mode: 'svg', - match: /\.svg$/i - }, - { - name: 'swift', - label: 'Swift', - alias: [], - mode: 'swift', - match: /\.swift$/i - }, - { - name: 'swig', - label: 'SWIG', - alias: [], - mode: 'swig', - match: /\.i$|\.swg$/i - }, - { - name: 'tcl', - label: 'Tcl', - alias: [], - mode: 'tcl', - match: /\.tcl$/i - }, - { - name: 'tex', - label: 'TeX', - alias: [], - mode: 'tex', - match: /\.tex$/i - }, - { - name: 'textile', - label: 'Textile', - alias: [], - mode: 'textile', - match: /\.textile$/i - }, - { - name: 'toml', - label: 'TOML', - alias: [], - mode: 'toml', - match: /\.toml$/i - }, - { - name: 'twig', - label: 'Twig', - alias: [], - mode: 'twig', - match: /\.twig$/i - }, - { - name: 'vala', - label: 'Vala', - alias: [], - mode: 'vala', - match: /\.vala$|\.vapi$/i - }, - { - name: 'vbscript', - label: 'VBScript', - alias: ['vbs', 'vbe'], - mode: 'vbscript', - match: /\.vbs$|\.vbe$/i - }, - { - name: 'velocity', - label: 'Velocity', - alias: [], - mode: 'velocity', - match: /\.vm$/i - }, - { - name: 'verilog', - label: 'Verilog', - alias: [], - mode: 'verilog', - match: /\.v$/i - }, - { - name: 'vhdl', - label: 'VHDL', - alias: [], - mode: 'vhdl', - match: /\.vhdl$/i - }, - { - name: 'xml', - label: 'XML', - alias: [], - mode: 'xml', - match: /\.xml$/i - }, - { - name: 'xquery', - label: 'XQuery', - alias: [], - mode: 'xquery', - match: /\.xq$|\.xqy$|\.xquery$/i - }, - { - name: 'yaml', - label: 'YAML', - alias: [], - mode: 'yaml', - match: /\.yaml$/i - } -] - -export default modes diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index af818b43..7378febf 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -7,19 +7,23 @@ import StarButton from './StarButton' import TagSelect from './TagSelect' import FolderSelect from './FolderSelect' import dataApi from 'browser/main/lib/dataApi' -import modes from 'browser/lib/modes' import { hashHistory } from 'react-router' import ee from 'browser/main/lib/eventEmitter' +import CodeMirror from 'codemirror' -function detectModeByFilename (filename) { - for (let key in modes) { - const mode = modes[key] - if (mode.match != null && mode.match.test(filename)) { - console.log(mode) - return mode.mode - } +function pass (name) { + switch (name) { + case 'ejs': + return 'Embedded Javascript' + case 'html_ruby': + return 'Embedded Ruby' + case 'objectivec': + return 'Objective C' + case 'text': + return 'Plain Text' + default: + return name } - return null } const electron = require('electron') @@ -283,8 +287,8 @@ class SnippetNoteDetail extends React.Component { handleNameInputChange (e, index) { let snippets = this.state.note.snippets.slice() snippets[index].name = e.target.value - let mode = detectModeByFilename(e.target.value.trim()) - if (mode != null) snippets[index].mode = mode + // let mode = detectModeByFilename(e.target.value.trim()) + // if (mode != null) snippets[index].mode = mode this.state.note.snippets = snippets this.setState({ @@ -297,9 +301,9 @@ class SnippetNoteDetail extends React.Component { handleModeButtonClick (index) { return (e) => { let menu = new Menu() - modes.forEach((mode) => { + CodeMirror.modeInfo.forEach((mode) => { menu.append(new MenuItem({ - label: mode.label, + label: mode.name, click: (e) => this.handleModeOptionClick(index, mode.name)(e) })) }) @@ -376,9 +380,9 @@ class SnippetNoteDetail extends React.Component { }) let viewList = note.snippets.map((snippet, index) => { let isActive = this.state.snippetIndex === index - let mode = snippet.mode === 'text' - ? null - : modes.filter((mode) => mode.name === snippet.mode)[0] + + let syntax = CodeMirror.findModeByName(pass(snippet.mode)) + if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') return
this.handleModeButtonClick(index)(e)} > - {mode == null + {snippet.mode == null ? 'Select Syntax...' - : mode.label + : syntax.name }  diff --git a/browser/main/global.styl b/browser/main/global.styl index c907a1a0..8ff0b134 100644 --- a/browser/main/global.styl +++ b/browser/main/global.styl @@ -87,3 +87,16 @@ body[data-theme="dark"] .ModalBase .modalBack background-color alpha(black, 60%) + +.CodeMirror + font-family inherit !important + line-height 1.4em + height 100% +.CodeMirror-focused .CodeMirror-selected + background #B1D7FE +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection + background #B1D7FE +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection + background #B1D7FE +::selection + background #B1D7FE diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 40748854..4cd96190 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -4,6 +4,8 @@ const OSX = global.process.platform === 'darwin' const electron = require('electron') const { ipcRenderer } = electron +let isInitialized = false + const defaultConfig = { zoom: 1, isSideNavFolded: false, @@ -19,11 +21,11 @@ const defaultConfig = { defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE' }, editor: { - theme: 'xcode', + theme: 'default', fontSize: '14', fontFamily: 'Monaco, Consolas', indentType: 'space', - indentSize: '4', + indentSize: '2', switchPreview: 'BLUR' // Available value: RIGHTCLICK, BLUR }, preview: { @@ -64,6 +66,20 @@ function get () { _save(config) } + if (!isInitialized) { + isInitialized = true + let editorTheme = document.getElementById('editorTheme') + if (editorTheme == null) { + editorTheme = document.createElement('link') + editorTheme.setAttribute('id', 'editorTheme') + editorTheme.setAttribute('rel', 'stylesheet') + document.head.appendChild(editorTheme) + } + if (config.editor.theme !== 'default') { + editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css') + } + } + return config } @@ -79,6 +95,15 @@ function set (updates) { document.body.setAttribute('data-theme', 'default') } + let editorTheme = document.getElementById('editorTheme') + if (editorTheme == null) { + editorTheme = document.createElement('link') + editorTheme.setAttribute('id', 'editorTheme') + editorTheme.setAttribute('rel', 'stylesheet') + document.head.appendChild(editorTheme) + } + editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newConfig.editor.theme + '.css') + ipcRenderer.send('config-renew', { config: get() }) diff --git a/browser/main/lib/dataApi/resolveStorageNotes.js b/browser/main/lib/dataApi/resolveStorageNotes.js index 21cc0a45..8622868d 100644 --- a/browser/main/lib/dataApi/resolveStorageNotes.js +++ b/browser/main/lib/dataApi/resolveStorageNotes.js @@ -21,10 +21,15 @@ function resolveStorageNotes (storage) { return /\.cson$/.test(notePath) }) .map(function parseCSONFile (notePath) { - let data = CSON.readFileSync(path.join(notesDirPath, notePath)) - data.key = path.basename(notePath, '.cson') - data.storage = storage.key - return data + try { + let data = CSON.readFileSync(path.join(notesDirPath, notePath)) + data.key = path.basename(notePath, '.cson') + data.storage = storage.key + return data + } catch (err) { + console.error(notePath) + throw err + } }) return Promise.resolve(notes) diff --git a/browser/main/modals/PreferencesModal/ConfigTab.js b/browser/main/modals/PreferencesModal/ConfigTab.js index d685b04d..2f72dc4c 100644 --- a/browser/main/modals/PreferencesModal/ConfigTab.js +++ b/browser/main/modals/PreferencesModal/ConfigTab.js @@ -4,10 +4,10 @@ import styles from './ConfigTab.styl' import hljsTheme from 'browser/lib/hljsThemes' import ConfigManager from 'browser/main/lib/ConfigManager' import store from 'browser/main/store' +import consts from 'browser/lib/consts' const electron = require('electron') const ipc = electron.ipcRenderer -const ace = window.ace const OSX = global.process.platform === 'darwin' @@ -153,7 +153,7 @@ class ConfigTab extends React.Component { {keymapAlert.message}

: null - let aceThemeList = ace.require('ace/ext/themelist') + let themes = consts.THEMES let hljsThemeList = hljsTheme() let { config } = this.state @@ -263,8 +263,8 @@ class ConfigTab extends React.Component { onChange={(e) => this.handleUIChange(e)} > { - aceThemeList.themes.map((theme) => { - return () + themes.map((theme) => { + return () }) } diff --git a/lib/finder.html b/lib/finder.html index bdd181f5..b9bc73e0 100644 --- a/lib/finder.html +++ b/lib/finder.html @@ -8,10 +8,9 @@ - - +