xtermFrontend.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Frontend } from './frontend'
  2. import { Terminal, ITheme } from 'xterm'
  3. import * as fit from 'xterm/lib/addons/fit/fit'
  4. import * as ligatures from 'xterm-addon-ligatures-tmp'
  5. import 'xterm/dist/xterm.css'
  6. import deepEqual = require('deep-equal')
  7. Terminal.applyAddon(fit)
  8. Terminal.applyAddon(ligatures)
  9. export class XTermFrontend extends Frontend {
  10. enableResizing = true
  11. xterm: Terminal
  12. private configuredFontSize = 0
  13. private zoom = 0
  14. private resizeHandler: any
  15. private configuredTheme: ITheme = {}
  16. constructor () {
  17. super()
  18. this.xterm = new Terminal({
  19. allowTransparency: true,
  20. enableBold: true,
  21. })
  22. this.xterm.on('data', data => {
  23. this.input.next(data)
  24. })
  25. this.xterm.on('resize', ({ cols, rows }) => {
  26. this.resize.next({ rows, columns: cols })
  27. })
  28. this.xterm.on('title', title => {
  29. this.title.next(title)
  30. })
  31. }
  32. attach (host: HTMLElement): void {
  33. this.xterm.open(host)
  34. this.ready.next(null)
  35. this.ready.complete()
  36. this.resizeHandler = () => (this.xterm as any).fit()
  37. window.addEventListener('resize', this.resizeHandler)
  38. this.resizeHandler()
  39. host.addEventListener('dragOver', (event: any) => this.dragOver.next(event))
  40. host.addEventListener('drop', event => this.drop.next(event))
  41. host.addEventListener('mousedown', event => this.mouseEvent.next(event as MouseEvent))
  42. host.addEventListener('mouseup', event => this.mouseEvent.next(event as MouseEvent))
  43. host.addEventListener('mousewheel', event => this.mouseEvent.next(event as MouseEvent))
  44. }
  45. detach (host: HTMLElement): void {
  46. window.removeEventListener('resize', this.resizeHandler)
  47. }
  48. getSelection (): string {
  49. return this.xterm.getSelection()
  50. }
  51. copySelection (): void {
  52. (navigator as any).clipboard.writeText(this.getSelection())
  53. }
  54. clearSelection (): void {
  55. this.xterm.clearSelection()
  56. }
  57. focus (): void {
  58. setTimeout(() => this.xterm.focus())
  59. }
  60. write (data: string): void {
  61. this.xterm.write(data)
  62. }
  63. clear (): void {
  64. this.xterm.clear()
  65. }
  66. visualBell (): void {
  67. (this.xterm as any).bell()
  68. }
  69. scrollToBottom (): void {
  70. this.xterm.scrollToBottom()
  71. }
  72. configure (config: any): void {
  73. this.xterm.setOption('fontFamily', `"${config.terminal.font}", "monospace-fallback", monospace`)
  74. this.xterm.setOption('bellStyle', config.terminal.bell)
  75. this.xterm.setOption('cursorStyle', {
  76. beam: 'bar'
  77. }[config.terminal.cuxrsor] || config.terminal.cursor)
  78. this.xterm.setOption('cursorBlink', config.terminal.cursorBlink)
  79. this.xterm.setOption('macOptionIsMeta', config.terminal.altIsMeta)
  80. // this.xterm.setOption('colors', )
  81. this.configuredFontSize = config.terminal.fontSize
  82. this.setFontSize()
  83. let theme: ITheme = {
  84. foreground: config.terminal.colorScheme.foreground,
  85. background: (config.terminal.background === 'colorScheme') ? config.terminal.colorScheme.background : 'transparent',
  86. cursor: config.terminal.colorScheme.cursor,
  87. }
  88. const colorNames = [
  89. 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
  90. 'brightBlack', 'brightRed', 'brightGreen', 'brightYellow', 'brightBlue', 'brightMagenta', 'brightCyan', 'brightWhite'
  91. ]
  92. for (let i = 0; i < colorNames.length; i++) {
  93. theme[colorNames[i]] = config.terminal.colorScheme.colors[i]
  94. }
  95. if (!deepEqual(this.configuredTheme, theme)) {
  96. this.xterm.setOption('theme', theme)
  97. this.configuredTheme = theme
  98. }
  99. if (config.terminal.ligatures && this.xterm.element) {
  100. (this.xterm as any).enableLigatures()
  101. }
  102. }
  103. setZoom (zoom: number): void {
  104. this.zoom = zoom
  105. this.setFontSize()
  106. }
  107. private setFontSize () {
  108. this.xterm.setOption('fontSize', this.configuredFontSize * Math.pow(1.1, this.zoom))
  109. }
  110. }