Skip to content

Commit

Permalink
Merge pull request #2768 from elfman/detect
Browse files Browse the repository at this point in the history
new feature: auto detect snippet language
  • Loading branch information
Rokt33r authored Jan 6, 2019
2 parents 05da826 + 082a078 commit 04ae8a8
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 8 deletions.
99 changes: 97 additions & 2 deletions browser/components/CodeEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'
import React from 'react'
import _ from 'lodash'
import CodeMirror from 'codemirror'
import hljs from 'highlight.js'
import 'codemirror-mode-elixir'
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
import convertModeName from 'browser/lib/convertModeName'
Expand Down Expand Up @@ -37,6 +38,85 @@ function translateHotkey (hotkey) {
return hotkey.replace(/\s*\+\s*/g, '-').replace(/Command/g, 'Cmd').replace(/Control/g, 'Ctrl')
}

const languageMaps = {
brainfuck: 'Brainfuck',
cpp: 'C++',
cs: 'C#',
clojure: 'Clojure',
'clojure-repl': 'ClojureScript',
cmake: 'CMake',
coffeescript: 'CoffeeScript',
crystal: 'Crystal',
css: 'CSS',
d: 'D',
dart: 'Dart',
delphi: 'Pascal',
diff: 'Diff',
django: 'Django',
dockerfile: 'Dockerfile',
ebnf: 'EBNF',
elm: 'Elm',
erlang: 'Erlang',
'erlang-repl': 'Erlang',
fortran: 'Fortran',
fsharp: 'F#',
gherkin: 'Gherkin',
go: 'Go',
groovy: 'Groovy',
haml: 'HAML',
haskell: 'Haskell',
haxe: 'Haxe',
http: 'HTTP',
ini: 'toml',
java: 'Java',
javascript: 'JavaScript',
json: 'JSON',
julia: 'Julia',
kotlin: 'Kotlin',
less: 'LESS',
livescript: 'LiveScript',
lua: 'Lua',
markdown: 'Markdown',
mathematica: 'Mathematica',
nginx: 'Nginx',
nsis: 'NSIS',
objectivec: 'Objective-C',
ocaml: 'Ocaml',
perl: 'Perl',
php: 'PHP',
powershell: 'PowerShell',
properties: 'Properties files',
protobuf: 'ProtoBuf',
python: 'Python',
puppet: 'Puppet',
q: 'Q',
r: 'R',
ruby: 'Ruby',
rust: 'Rust',
sas: 'SAS',
scala: 'Scala',
scheme: 'Scheme',
scss: 'SCSS',
shell: 'Shell',
smalltalk: 'Smalltalk',
sml: 'SML',
sql: 'SQL',
stylus: 'Stylus',
swift: 'Swift',
tcl: 'Tcl',
tex: 'LaTex',
typescript: 'TypeScript',
twig: 'Twig',
vbnet: 'VB.NET',
vbscript: 'VBScript',
verilog: 'Verilog',
vhdl: 'VHDL',
xml: 'HTML',
xquery: 'XQuery',
yaml: 'YAML',
elixir: 'Elixir'
}

export default class CodeEditor extends React.Component {
constructor (props) {
super(props)
Expand Down Expand Up @@ -274,7 +354,11 @@ export default class CodeEditor extends React.Component {
extraKeys: this.defaultKeyMap
})

this.setMode(this.props.mode)
if (!this.props.mode && this.props.value && this.props.autoDetect) {
this.autoDetectLanguage(this.props.value)
} else {
this.setMode(this.props.mode)
}

this.editor.on('focus', this.focusHandler)
this.editor.on('blur', this.blurHandler)
Expand Down Expand Up @@ -644,7 +728,7 @@ export default class CodeEditor extends React.Component {
}

setMode (mode) {
let syntax = CodeMirror.findModeByName(convertModeName(mode))
let syntax = CodeMirror.findModeByName(convertModeName(mode || 'text'))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')

this.editor.setOption('mode', syntax.mime)
Expand Down Expand Up @@ -796,6 +880,11 @@ export default class CodeEditor extends React.Component {
this.editor.replaceSelection(imageMd)
}

autoDetectLanguage (content) {
const res = hljs.highlightAuto(content, Object.keys(languageMaps))
this.setMode(languageMaps[res.language])
}

handlePaste (editor, forceSmartPaste) {
const { storageKey, noteKey, fetchUrlTitle, enableSmartPaste } = this.props

Expand Down Expand Up @@ -892,6 +981,10 @@ export default class CodeEditor extends React.Component {
this.handlePasteText(editor, pastedTxt)
}
}

if (!this.props.mode && this.props.autoDetect) {
this.autoDetectLanguage(editor.doc.getValue())
}
}

handleScroll (e) {
Expand Down Expand Up @@ -1091,6 +1184,7 @@ CodeEditor.propTypes = {
onBlur: PropTypes.func,
onChange: PropTypes.func,
readOnly: PropTypes.bool,
autoDetect: PropTypes.bool,
spellCheck: PropTypes.bool
}

Expand All @@ -1102,5 +1196,6 @@ CodeEditor.defaultProps = {
fontFamily: 'Monaco, Consolas',
indentSize: 4,
indentType: 'space',
autoDetect: false,
spellCheck: false
}
4 changes: 3 additions & 1 deletion browser/lib/newNote.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
tags = params.tagname.split(' ')
}

const defaultLanguage = config.editor.snippetDefaultLanguage === 'Auto Detect' ? null : config.editor.snippetDefaultLanguage

return dataApi
.createNote(storage, {
type: 'SNIPPET_NOTE',
Expand All @@ -56,7 +58,7 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
snippets: [
{
name: '',
mode: config.editor.snippetDefaultLanguage || 'text',
mode: defaultLanguage,
content: '',
linesHighlighted: []
}
Expand Down
13 changes: 8 additions & 5 deletions browser/main/Detail/SnippetNoteDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -599,12 +599,14 @@ class SnippetNoteDetail extends React.Component {
}

addSnippet () {
const { config } = this.props
const { config: { editor: { snippetDefaultLanguage } } } = this.props
const { note } = this.state

const defaultLanguage = snippetDefaultLanguage === 'Auto Detect' ? null : snippetDefaultLanguage

note.snippets = note.snippets.concat([{
name: '',
mode: config.editor.snippetDefaultLanguage || 'text',
mode: defaultLanguage,
content: '',
linesHighlighted: []
}])
Expand Down Expand Up @@ -672,6 +674,8 @@ class SnippetNoteDetail extends React.Component {
const storageKey = note.storage
const folderKey = note.folder

const autoDetect = config.editor.snippetDefaultLanguage === 'Auto Detect'

let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
Expand All @@ -696,8 +700,6 @@ class SnippetNoteDetail extends React.Component {

const viewList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(convertModeName(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
return <div styleName='tabView'
key={index}
style={{zIndex: isActive ? 5 : 4}}
Expand All @@ -713,7 +715,7 @@ class SnippetNoteDetail extends React.Component {
storageKey={storageKey}
/>
: <CodeEditor styleName='tabView-content'
mode={snippet.mode}
mode={snippet.mode || (autoDetect ? null : config.editor.snippetDefaultLanguage)}
value={snippet.content}
linesHighlighted={snippet.linesHighlighted}
theme={config.editor.theme}
Expand All @@ -733,6 +735,7 @@ class SnippetNoteDetail extends React.Component {
ref={'code-' + index}
enableSmartPaste={config.editor.enableSmartPaste}
hotkey={config.hotkey}
autoDetect={autoDetect}
/>
}
</div>
Expand Down
1 change: 1 addition & 0 deletions browser/main/modals/PreferencesModal/UiTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ class UiTab extends React.Component {
ref='editorSnippetDefaultLanguage'
onChange={(e) => this.handleUIChange(e)}
>
<option key='Auto Detect' value='Auto Detect'>Auto Detect</option>
{
_.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => (<option key={name} value={name}>{name}</option>))
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"flowchart.js": "^1.6.5",
"font-awesome": "^4.3.0",
"fs-extra": "^5.0.0",
"highlight.js": "^9.13.1",
"i18n-2": "^0.7.2",
"iconv-lite": "^0.4.19",
"immutable": "^3.8.1",
Expand Down

0 comments on commit 04ae8a8

Please sign in to comment.