@electerm/electerm-react 1.37.6 → 1.37.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -307,6 +307,7 @@ export const localAddrBookmarkLsKey = 'local-addr-bookmark-keys'
307
307
  export const sshTunnelHelpLink = 'https://github.com/electerm/electerm/wiki/How-to-use-ssh-tunnel'
308
308
  export const batchOpHelpLink = 'https://github.com/electerm/electerm/wiki/batch-operation'
309
309
  export const proxyHelpLink = 'https://github.com/electerm/electerm/wiki/proxy-format'
310
+ export const regexHelpLink = 'https://github.com/electerm/electerm/wiki/Terminal-keywords-highlight-regular-expression-exmaples'
310
311
  export const modals = {
311
312
  hide: 0,
312
313
  setting: 1,
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  export default (basePath, nameOrDot) => {
9
- const sep = basePath.includes('\\') || basePath.includes(':')
9
+ const sep = basePath.includes('\\') || basePath.includes(':\\')
10
10
  ? '\\'
11
11
  : '/'
12
12
  if (nameOrDot === '..') {
@@ -18,7 +18,7 @@ export default (basePath, nameOrDot) => {
18
18
  const res = arr.slice(0, length - 1).join(sep)
19
19
  return res || '/'
20
20
  }
21
- const pre = nameOrDot.includes(':') && basePath === '/'
21
+ const pre = nameOrDot.includes(':\\') && basePath === '/'
22
22
  ? ''
23
23
  : basePath
24
24
  return pre +
@@ -30,16 +30,31 @@ export default function KeywordForm (props) {
30
30
  props.submit(data)
31
31
  }
32
32
 
33
+ function checker (_, value) {
34
+ try {
35
+ return Promise.resolve(!!new RegExp(`(${value})`, 'gi'))
36
+ } catch (e) {
37
+ console.log(e)
38
+ return Promise.reject(e)
39
+ }
40
+ }
41
+
33
42
  function renderItem (field, i, add, remove) {
34
43
  return (
35
44
  <Space
36
45
  align='center'
37
46
  key={field.key}
47
+ className='mg3r'
38
48
  >
39
49
  <FormItem
40
50
  hasFeedback
41
51
  >
42
- <FormItem noStyle required name={[field.name, 'keyword']}>
52
+ <FormItem
53
+ noStyle
54
+ required
55
+ name={[field.name, 'keyword']}
56
+ rules={[{ validator: checker }]}
57
+ >
43
58
  <Input
44
59
  addonBefore={renderBefore(field.name)}
45
60
  />
@@ -17,7 +17,8 @@ import {
17
17
  import deepCopy from 'json-deep-copy'
18
18
  import {
19
19
  noTerminalBgValue,
20
- rendererTypes
20
+ rendererTypes,
21
+ regexHelpLink
21
22
  } from '../../common/constants'
22
23
  import defaultSettings from '../../common/default-setting'
23
24
  import ShowItem from '../common/show-item'
@@ -25,6 +26,7 @@ import { osResolve } from '../../common/resolve'
25
26
  import { isNumber, isNaN } from 'lodash-es'
26
27
  import mapper from '../../common/auto-complete-data-mapper'
27
28
  import KeywordForm from './keywords-form'
29
+ import Link from '../common/external-link'
28
30
  import HelpIcon from '../common/help-icon'
29
31
  import './setting.styl'
30
32
 
@@ -406,7 +408,15 @@ export default class SettingTerminal extends Component {
406
408
  },
407
409
  submit: this.handleSubmitKeywords
408
410
  }
409
- const terminalLogPath = appPath ? osResolve(appPath, 'electerm', 'session_logs') : window.et.sessionLogPath
411
+ const terminalLogPath = appPath
412
+ ? osResolve(appPath, 'electerm', 'session_logs')
413
+ : window.et.sessionLogPath
414
+ const tip = (
415
+ <div>
416
+ <span className='mg1r'>{f('supportRegexp')}</span>
417
+ <Link to={regexHelpLink}>wiki</Link>
418
+ </div>
419
+ )
410
420
  return (
411
421
  <div className='form-wrap pd1y pd2x'>
412
422
  <div className='pd1y font16 bold'>
@@ -451,7 +461,7 @@ export default class SettingTerminal extends Component {
451
461
  <div className='pd1b'>
452
462
  <span className='inline-title mg1r'>{f('keywordsHighlight')}</span>
453
463
  <HelpIcon
454
- title={f('supportRegexp')}
464
+ title={tip}
455
465
  />
456
466
  </div>
457
467
  <KeywordForm
@@ -480,7 +490,6 @@ export default class SettingTerminal extends Component {
480
490
  ))}
481
491
  {
482
492
  [
483
- 'addTimeStampToTermLog',
484
493
  'cursorBlink',
485
494
  'rightClickSelectsWord',
486
495
  'pasteWhenContextMenu',
@@ -12,17 +12,17 @@ const isRemote = true
12
12
  const temp = '/tmp'
13
13
 
14
14
  export async function zipCmd (pid, sessionId, filePath) {
15
- // tar -czf bin.tar.gz bin
15
+ // tar -czf bin.tar bin
16
16
  const id = generate()
17
17
  const { path, name } = getFolderFromFilePath(filePath, isRemote)
18
- const np = resolve(temp, `electerm-${id}.tar.gz`)
19
- const cmd = `tar -C ${path} -czf ${np} ${name}`
18
+ const np = resolve(temp, `electerm-${id}.tar`)
19
+ const cmd = `tar -C ${path} -cf ${np} ${name}`
20
20
  await runCmd(pid, sessionId, cmd)
21
21
  return np
22
22
  }
23
23
 
24
24
  export function unzipCmd (pid, sessionId, from, to) {
25
- const cmd = `tar -xzf "${from}" -C "${to}"`
25
+ const cmd = `tar -xf "${from}" -C "${to}"`
26
26
  return runCmd(pid, sessionId, cmd)
27
27
  }
28
28
 
@@ -5,7 +5,6 @@
5
5
 
6
6
  import React from 'react'
7
7
  import { shortcutExtend } from './shortcut-handler.js'
8
- import { throttle } from 'lodash-es'
9
8
 
10
9
  class ShortcutControl extends React.PureComponent {
11
10
  componentDidMount () {
@@ -28,18 +27,18 @@ class ShortcutControl extends React.PureComponent {
28
27
  window.store.onNewSsh()
29
28
  }
30
29
 
31
- togglefullscreenShortcut = throttle((e) => {
30
+ togglefullscreenShortcut = (e) => {
32
31
  e.stopPropagation()
33
32
  const x = document.querySelector('.term-fullscreen-control') ||
34
- document.querySelector('.term-fullscreen-control1')
33
+ document.querySelector('.session-current .term-fullscreen-control1')
35
34
  x && x.click()
36
- }, 300)
35
+ }
37
36
 
38
- splitShortcut = throttle((e) => {
37
+ splitShortcut = (e) => {
39
38
  e.stopPropagation()
40
- const x = document.querySelector('.icon-split')
39
+ const x = document.querySelector('.session-current .icon-split')
41
40
  x && x.click()
42
- }, 1200)
41
+ }
43
42
 
44
43
  zoominShortcut = (e) => {
45
44
  e.stopPropagation()
@@ -3,10 +3,32 @@ import shortcutsDefaultsGen from './shortcuts-defaults.js'
3
3
  import {
4
4
  isMacJs
5
5
  } from '../../common/constants'
6
+ import { throttle } from 'lodash-es'
6
7
 
7
8
  function buildConfig (config, filter = d => d) {
8
9
  const defs = shortcutsDefaultsGen().filter(filter)
9
10
  const { shortcuts = {} } = config
11
+ return defs.reduce((p, c) => {
12
+ const propName = isMacJs ? 'shortcutMac' : 'shortcut'
13
+ if (isMacJs && c.skipMac) {
14
+ return p
15
+ }
16
+ const name = c.name + '_' + propName
17
+ const [type, func] = c.name.split('_')
18
+ return {
19
+ ...p,
20
+ [name]: {
21
+ shortcut: c.readonly ? c[propName] : (shortcuts[name] || c[propName]),
22
+ type,
23
+ func
24
+ }
25
+ }
26
+ }, {})
27
+ }
28
+
29
+ function buildConfigForSearch (config) {
30
+ const defs = shortcutsDefaultsGen()
31
+ const { shortcuts = {} } = config
10
32
  return defs.reduce((p, c) => {
11
33
  const propName = isMacJs ? 'shortcutMac' : 'shortcut'
12
34
  const name = c.name + '_' + propName
@@ -23,7 +45,7 @@ function buildConfig (config, filter = d => d) {
23
45
  }
24
46
 
25
47
  export function shortcutExtend (Cls) {
26
- Cls.prototype.handleKeyboardEvent = function (event) {
48
+ Cls.prototype.handleKeyboardEvent = throttle(function (event) {
27
49
  const {
28
50
  code,
29
51
  ctrlKey,
@@ -45,7 +67,7 @@ export function shortcutExtend (Cls) {
45
67
  (shiftKey ? 'shift+' : '') +
46
68
  (altKey ? 'alt+' : '') +
47
69
  codeK.toLowerCase()
48
- const shortcutsConfig = buildConfig(this.props.config, d => !d.readonly)
70
+ const shortcutsConfig = buildConfig(this.props.config, d => !d.hidden)
49
71
  const keys = Object.keys(shortcutsConfig)
50
72
  const len = keys.length
51
73
  for (let i = 0; i < len; i++) {
@@ -54,19 +76,19 @@ export function shortcutExtend (Cls) {
54
76
  const funcName = conf.func + 'Shortcut'
55
77
  if (conf.shortcut.split(',').includes(r)) {
56
78
  if (this[funcName]) {
57
- this[funcName](event)
58
- } else {
59
- return false
79
+ return this[funcName](event)
80
+ } else if (this.isTerm) {
81
+ return true
60
82
  }
61
83
  }
62
84
  }
63
- }
85
+ }, 300)
64
86
  return Cls
65
87
  }
66
88
 
67
89
  export function shortcutDescExtend (Cls) {
68
90
  Cls.prototype.getShortcut = function (name) {
69
- const shortcutsConfig = buildConfig(this.props.config)
91
+ const shortcutsConfig = buildConfigForSearch(this.props.config)
70
92
  const propName = isMacJs ? 'shortcutMac' : 'shortcut'
71
93
  const n = `${name}_${propName}`
72
94
  return shortcutsConfig[n].shortcut
@@ -49,18 +49,21 @@ export default () => {
49
49
  name: 'terminal_selectAll',
50
50
  shortcut: 'ctrl+a,ctrl+shift+a',
51
51
  shortcutMac: 'meta+a',
52
+ skipMac: true,
52
53
  readonly: true
53
54
  },
54
55
  {
55
56
  name: 'terminal_copy',
56
57
  shortcut: 'ctrl+c,ctrl+shift+c',
57
58
  shortcutMac: 'meta+c',
59
+ skipMac: true,
58
60
  readonly: true
59
61
  },
60
62
  {
61
63
  name: 'terminal_paste',
62
64
  shortcut: 'ctrl+v,ctrl+shift+v',
63
65
  shortcutMac: 'meta+v',
66
+ hidden: true,
64
67
  readonly: true
65
68
  },
66
69
  {
@@ -8,7 +8,7 @@ export default function tabTitle (props) {
8
8
  ? { color }
9
9
  : {}
10
10
  return (
11
- <span>
11
+ <span className='tab-title'>
12
12
  <span style={styleTag}>♦</span> {tabCount}. {title}
13
13
  </span>
14
14
  )
@@ -35,8 +35,12 @@ export class KeywordHighlighterAddon {
35
35
  color = 'red'
36
36
  } = obj || {}
37
37
  if (keyword) {
38
- const regex = new RegExp(`(${keyword})`, 'gi')
39
- text = text.replace(regex, this.colorize(color))
38
+ try {
39
+ const regex = new RegExp(`(${keyword})`, 'gi')
40
+ text = text.replace(regex, this.colorize(color))
41
+ } catch (e) {
42
+ window.store.onError(e)
43
+ }
40
44
  }
41
45
  }
42
46
  return text
@@ -41,6 +41,7 @@ import { WebLinksAddon } from 'xterm-addon-web-links'
41
41
  import { SerializeAddon } from 'xterm-addon-serialize'
42
42
  import { CanvasAddon } from 'xterm-addon-canvas'
43
43
  import { WebglAddon } from 'xterm-addon-webgl'
44
+ import { LigaturesAddon } from 'xterm-addon-ligatures'
44
45
  import getProxy from '../../common/get-proxy'
45
46
  import { Zmodem, AddonZmodem } from './xterm-zmodem'
46
47
  import { Unicode11Addon } from 'xterm-addon-unicode11'
@@ -86,6 +87,8 @@ class Term extends Component {
86
87
  }
87
88
  }
88
89
 
90
+ isTerm = true
91
+
89
92
  dataCache = ''
90
93
 
91
94
  componentDidMount () {
@@ -233,15 +236,14 @@ class Term extends Component {
233
236
  this.term.selectAll()
234
237
  }
235
238
 
236
- // copyShortcut = (e) => {
237
- // const sel = this.term.getSelection()
238
- // if (sel) {
239
- // e.stopPropagation()
240
- // e.preventDefault()
241
- // this.copySelectionToClipboard()
242
- // return false
243
- // }
244
- // }
239
+ copyShortcut = (e) => {
240
+ const sel = this.term.getSelection()
241
+ if (sel) {
242
+ e.stopPropagation()
243
+ this.copySelectionToClipboard()
244
+ return false
245
+ }
246
+ }
245
247
 
246
248
  searchShortcut = (e) => {
247
249
  e.stopPropagation()
@@ -767,12 +769,32 @@ class Term extends Component {
767
769
  }
768
770
  }
769
771
 
772
+ parse (rawText) {
773
+ let result = ''
774
+ const len = rawText.length
775
+ for (let i = 0; i < len; i++) {
776
+ if (rawText[i] === '\b') {
777
+ result = result.slice(0, -1)
778
+ } else {
779
+ result += rawText[i]
780
+ }
781
+ }
782
+ return result
783
+ }
784
+
785
+ onKey = ({ key }) => {
786
+ if (key === '\x7F') {
787
+ this.dataCache = this.dataCache.slice(0, -1)
788
+ } else {
789
+ this.dataCache += key
790
+ }
791
+ }
792
+
770
793
  onData = (d) => {
771
- if (!d.includes('\r') && !d.includes('\r')) {
772
- this.dataCache += d
794
+ if (!d.includes('\r')) {
773
795
  delete this.userTypeExit
774
796
  } else {
775
- const data = this.dataCache.trim()
797
+ const data = this.parse(this.dataCache.trim())
776
798
  this.dataCache = ''
777
799
  if (data === 'exit') {
778
800
  this.userTypeExit = true
@@ -815,27 +837,31 @@ class Term extends Component {
815
837
  fontSize: tab.fontSize || config.fontSize,
816
838
  screenReaderMode: config.screenReaderMode
817
839
  })
840
+
841
+ // term.onLineFeed(this.onLineFeed)
842
+ // term.onTitleChange(this.onTitleChange)
843
+ term.onSelectionChange(this.onSelection)
844
+ this.loadState(term)
845
+ term.open(document.getElementById(id), true)
846
+ this.loadRenderer(term, config)
847
+ term.textarea.addEventListener('focus', this.setActive)
848
+ term.onKey(this.onKey)
849
+ // term.textarea.addEventListener('blur', this.onBlur)
850
+
851
+ // term.on('keydown', this.handleEvent)
818
852
  this.fitAddon = new FitAddon()
819
853
  this.searchAddon = new SearchAddon()
854
+ const ligtureAddon = new LigaturesAddon()
820
855
  this.searchAddon.onDidChangeResults(this.onSearchResultsChange)
821
856
  const unicode11Addon = new Unicode11Addon()
822
857
  this.serializeAddon = new SerializeAddon()
823
858
  term.loadAddon(this.serializeAddon)
824
859
  term.loadAddon(unicode11Addon)
860
+ term.loadAddon(ligtureAddon)
825
861
  // activate the new version
826
862
  term.unicode.activeVersion = '11'
827
863
  term.loadAddon(this.fitAddon)
828
864
  term.loadAddon(this.searchAddon)
829
- // term.onLineFeed(this.onLineFeed)
830
- // term.onTitleChange(this.onTitleChange)
831
- term.onSelectionChange(this.onSelection)
832
- this.loadState(term)
833
- term.open(document.getElementById(id), true)
834
- this.loadRenderer(term, config)
835
- term.textarea.addEventListener('focus', this.setActive)
836
- // term.textarea.addEventListener('blur', this.onBlur)
837
-
838
- // term.on('keydown', this.handleEvent)
839
865
  term.onData(this.onData)
840
866
  this.term = term
841
867
  term.attachCustomKeyEventHandler(this.handleKeyboardEvent.bind(this))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.37.6",
3
+ "version": "1.37.18",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",