mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 01:36:22 +00:00
new feature: auto detect snippet language
only try to detect after pasting and mode has not been set and default snippet language is "Auto Detect"
This commit is contained in:
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import CodeMirror from 'codemirror'
|
import CodeMirror from 'codemirror'
|
||||||
|
import hljs from 'highlight.js'
|
||||||
import 'codemirror-mode-elixir'
|
import 'codemirror-mode-elixir'
|
||||||
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
||||||
import convertModeName from 'browser/lib/convertModeName'
|
import convertModeName from 'browser/lib/convertModeName'
|
||||||
@@ -37,6 +38,85 @@ function translateHotkey (hotkey) {
|
|||||||
return hotkey.replace(/\s*\+\s*/g, '-').replace(/Command/g, 'Cmd').replace(/Control/g, 'Ctrl')
|
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 {
|
export default class CodeEditor extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
@@ -274,7 +354,11 @@ export default class CodeEditor extends React.Component {
|
|||||||
extraKeys: this.defaultKeyMap
|
extraKeys: this.defaultKeyMap
|
||||||
})
|
})
|
||||||
|
|
||||||
this.setMode(this.props.mode)
|
if (!this.props.mode && this.props.value) {
|
||||||
|
this.autoDetectLanguage(this.props.value)
|
||||||
|
} else {
|
||||||
|
this.setMode(this.props.mode)
|
||||||
|
}
|
||||||
|
|
||||||
this.editor.on('focus', this.focusHandler)
|
this.editor.on('focus', this.focusHandler)
|
||||||
this.editor.on('blur', this.blurHandler)
|
this.editor.on('blur', this.blurHandler)
|
||||||
@@ -644,7 +728,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setMode (mode) {
|
setMode (mode) {
|
||||||
let syntax = CodeMirror.findModeByName(convertModeName(mode))
|
let syntax = CodeMirror.findModeByName(convertModeName(mode || 'text'))
|
||||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||||
|
|
||||||
this.editor.setOption('mode', syntax.mime)
|
this.editor.setOption('mode', syntax.mime)
|
||||||
@@ -796,6 +880,11 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.editor.replaceSelection(imageMd)
|
this.editor.replaceSelection(imageMd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
autoDetectLanguage (content) {
|
||||||
|
const res = hljs.highlightAuto(content, Object.keys(languageMaps))
|
||||||
|
this.setMode(languageMaps[res.language])
|
||||||
|
}
|
||||||
|
|
||||||
handlePaste (editor, forceSmartPaste) {
|
handlePaste (editor, forceSmartPaste) {
|
||||||
const { storageKey, noteKey, fetchUrlTitle, enableSmartPaste } = this.props
|
const { storageKey, noteKey, fetchUrlTitle, enableSmartPaste } = this.props
|
||||||
|
|
||||||
@@ -892,6 +981,10 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.handlePasteText(editor, pastedTxt)
|
this.handlePasteText(editor, pastedTxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.props.mode) {
|
||||||
|
this.autoDetectLanguage(editor.doc.getValue())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScroll (e) {
|
handleScroll (e) {
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
|
|||||||
tags = params.tagname.split(' ')
|
tags = params.tagname.split(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultLanguage = config.editor.snippetDefaultLanguage === 'Auto Detect' ? null : config.editor.snippetDefaultLanguage
|
||||||
|
|
||||||
return dataApi
|
return dataApi
|
||||||
.createNote(storage, {
|
.createNote(storage, {
|
||||||
type: 'SNIPPET_NOTE',
|
type: 'SNIPPET_NOTE',
|
||||||
@@ -56,7 +58,7 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
|
|||||||
snippets: [
|
snippets: [
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
mode: config.editor.snippetDefaultLanguage || 'text',
|
mode: defaultLanguage,
|
||||||
content: '',
|
content: '',
|
||||||
linesHighlighted: []
|
linesHighlighted: []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -599,12 +599,14 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSnippet () {
|
addSnippet () {
|
||||||
const { config } = this.props
|
const { config: { editor: { snippetDefaultLanguage } } } = this.props
|
||||||
const { note } = this.state
|
const { note } = this.state
|
||||||
|
|
||||||
|
const defaultLanguage = snippetDefaultLanguage === 'Auto Detect' ? null : snippetDefaultLanguage
|
||||||
|
|
||||||
note.snippets = note.snippets.concat([{
|
note.snippets = note.snippets.concat([{
|
||||||
name: '',
|
name: '',
|
||||||
mode: config.editor.snippetDefaultLanguage || 'text',
|
mode: defaultLanguage,
|
||||||
content: '',
|
content: '',
|
||||||
linesHighlighted: []
|
linesHighlighted: []
|
||||||
}])
|
}])
|
||||||
@@ -696,8 +698,6 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
|
|
||||||
const viewList = note.snippets.map((snippet, index) => {
|
const viewList = note.snippets.map((snippet, index) => {
|
||||||
const isActive = this.state.snippetIndex === 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'
|
return <div styleName='tabView'
|
||||||
key={index}
|
key={index}
|
||||||
style={{zIndex: isActive ? 5 : 4}}
|
style={{zIndex: isActive ? 5 : 4}}
|
||||||
|
|||||||
@@ -481,6 +481,7 @@ class UiTab extends React.Component {
|
|||||||
ref='editorSnippetDefaultLanguage'
|
ref='editorSnippetDefaultLanguage'
|
||||||
onChange={(e) => this.handleUIChange(e)}
|
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>))
|
_.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => (<option key={name} value={name}>{name}</option>))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
"flowchart.js": "^1.6.5",
|
"flowchart.js": "^1.6.5",
|
||||||
"font-awesome": "^4.3.0",
|
"font-awesome": "^4.3.0",
|
||||||
"fs-extra": "^5.0.0",
|
"fs-extra": "^5.0.0",
|
||||||
|
"highlight.js": "^9.13.1",
|
||||||
"i18n-2": "^0.7.2",
|
"i18n-2": "^0.7.2",
|
||||||
"iconv-lite": "^0.4.19",
|
"iconv-lite": "^0.4.19",
|
||||||
"immutable": "^3.8.1",
|
"immutable": "^3.8.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user