mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #492 from Tyriar/480_cursor_style
Implement CSI Ps SP q Set cursor style
This commit is contained in:
@@ -20,7 +20,3 @@ h1 {
|
||||
color: #fafafa;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#terminal-container .terminal:focus .terminal-cursor {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { assert } from 'chai';
|
||||
import { InputHandler } from './InputHandler';
|
||||
|
||||
describe('InputHandler', () => {
|
||||
describe('setCursorStyle', () => {
|
||||
it('should call Terminal.setOption with correct params', () => {
|
||||
let options = {};
|
||||
let terminal = {
|
||||
setOption: (option, value) => options[option] = value
|
||||
};
|
||||
let inputHandler = new InputHandler(terminal);
|
||||
|
||||
inputHandler.setCursorStyle([0]);
|
||||
assert.equal(options['cursorStyle'], 'block');
|
||||
assert.equal(options['cursorBlink'], true);
|
||||
|
||||
options = {};
|
||||
inputHandler.setCursorStyle([1]);
|
||||
assert.equal(options['cursorStyle'], 'block');
|
||||
assert.equal(options['cursorBlink'], true);
|
||||
|
||||
options = {};
|
||||
inputHandler.setCursorStyle([2]);
|
||||
assert.equal(options['cursorStyle'], 'block');
|
||||
assert.equal(options['cursorBlink'], false);
|
||||
|
||||
options = {};
|
||||
inputHandler.setCursorStyle([3]);
|
||||
assert.equal(options['cursorStyle'], 'underline');
|
||||
assert.equal(options['cursorBlink'], true);
|
||||
|
||||
options = {};
|
||||
inputHandler.setCursorStyle([4]);
|
||||
assert.equal(options['cursorStyle'], 'underline');
|
||||
assert.equal(options['cursorBlink'], false);
|
||||
|
||||
options = {};
|
||||
inputHandler.setCursorStyle([5]);
|
||||
assert.equal(options['cursorStyle'], 'bar');
|
||||
assert.equal(options['cursorBlink'], true);
|
||||
|
||||
options = {};
|
||||
inputHandler.setCursorStyle([6]);
|
||||
assert.equal(options['cursorStyle'], 'bar');
|
||||
assert.equal(options['cursorBlink'], false);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1392,6 +1392,36 @@ export class InputHandler implements IInputHandler {
|
||||
this._terminal.charsets = [null]; // ??
|
||||
}
|
||||
|
||||
/**
|
||||
* CSI Ps SP q Set cursor style (DECSCUSR, VT520).
|
||||
* Ps = 0 -> blinking block.
|
||||
* Ps = 1 -> blinking block (default).
|
||||
* Ps = 2 -> steady block.
|
||||
* Ps = 3 -> blinking underline.
|
||||
* Ps = 4 -> steady underline.
|
||||
* Ps = 5 -> blinking bar (xterm).
|
||||
* Ps = 6 -> steady bar (xterm).
|
||||
*/
|
||||
public setCursorStyle(params?: number[]): void {
|
||||
const param = params[0] < 1 ? 1 : params[0];
|
||||
switch (param) {
|
||||
case 1:
|
||||
case 2:
|
||||
this._terminal.setOption('cursorStyle', 'block');
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
this._terminal.setOption('cursorStyle', 'underline');
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
this._terminal.setOption('cursorStyle', 'bar');
|
||||
break;
|
||||
}
|
||||
const isBlinking = param % 2 === 1;
|
||||
this._terminal.setOption('cursorBlink', isBlinking);
|
||||
}
|
||||
|
||||
/**
|
||||
* CSI Ps ; Ps r
|
||||
* Set Scrolling Region [top;bottom] (default = full size of win-
|
||||
|
||||
@@ -79,6 +79,7 @@ export interface IInputHandler {
|
||||
/** CSI m */ charAttributes(params?: number[]): void;
|
||||
/** CSI n */ deviceStatus(params?: number[]): void;
|
||||
/** CSI p */ softReset(params?: number[]): void;
|
||||
/** CSI q */ setCursorStyle(params?: number[]): void;
|
||||
/** CSI r */ setScrollRegion(params?: number[]): void;
|
||||
/** CSI s */ saveCursor(params?: number[]): void;
|
||||
/** CSI u */ restoreCursor(params?: number[]): void;
|
||||
|
||||
+7
-2
@@ -95,7 +95,7 @@ csiParamStateHandler[' '] = (parser) => parser.setPostfix(' ');
|
||||
csiParamStateHandler['\''] = (parser) => parser.setPostfix('\'');
|
||||
csiParamStateHandler[';'] = (parser) => parser.finalizeParam();
|
||||
|
||||
const csiStateHandler: {[key: string]: (handler: IInputHandler, params: number[], prefix: string) => void} = {};
|
||||
const csiStateHandler: {[key: string]: (handler: IInputHandler, params: number[], prefix: string, postfix: string) => void} = {};
|
||||
csiStateHandler['@'] = (handler, params, prefix) => handler.insertChars(params);
|
||||
csiStateHandler['A'] = (handler, params, prefix) => handler.cursorUp(params);
|
||||
csiStateHandler['B'] = (handler, params, prefix) => handler.cursorDown(params);
|
||||
@@ -136,6 +136,11 @@ csiStateHandler['p'] = (handler, params, prefix) => {
|
||||
case '!': handler.softReset(params); break;
|
||||
}
|
||||
};
|
||||
csiStateHandler['q'] = (handler, params, prefix, postfix) => {
|
||||
if (postfix === ' ') {
|
||||
handler.setCursorStyle(params);
|
||||
}
|
||||
};
|
||||
csiStateHandler['r'] = (handler, params) => handler.setScrollRegion(params);
|
||||
csiStateHandler['s'] = (handler, params) => handler.saveCursor(params);
|
||||
csiStateHandler['u'] = (handler, params) => handler.restoreCursor(params);
|
||||
@@ -472,7 +477,7 @@ export class Parser {
|
||||
|
||||
case ParserState.CSI:
|
||||
if (ch in csiStateHandler) {
|
||||
csiStateHandler[ch](this._inputHandler, this._terminal.params, this._terminal.prefix);
|
||||
csiStateHandler[ch](this._inputHandler, this._terminal.params, this._terminal.prefix, this._terminal.postfix);
|
||||
} else {
|
||||
this._terminal.error('Unknown CSI code: %s.', ch);
|
||||
}
|
||||
|
||||
+34
-2
@@ -71,7 +71,7 @@
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.terminal .terminal-cursor {
|
||||
.terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) .terminal-cursor {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
@@ -82,7 +82,7 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.terminal.focus.xterm-cursor-blink .terminal-cursor {
|
||||
.terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus.xterm-cursor-blink .terminal-cursor {
|
||||
animation: xterm-cursor-blink 1.2s infinite step-end;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
.terminal.xterm-cursor-style-bar .terminal-cursor,
|
||||
.terminal.xterm-cursor-style-underline .terminal-cursor {
|
||||
position: relative;
|
||||
}
|
||||
.terminal.xterm-cursor-style-bar .terminal-cursor::before,
|
||||
.terminal.xterm-cursor-style-underline .terminal-cursor::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
}
|
||||
.terminal.xterm-cursor-style-bar .terminal-cursor::before {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 1px;
|
||||
}
|
||||
.terminal.xterm-cursor-style-underline .terminal-cursor::before {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
}
|
||||
.terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink .terminal-cursor::before,
|
||||
.terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink .terminal-cursor::before {
|
||||
animation: xterm-cursor-non-bar-blink 1.2s infinite step-end;
|
||||
}
|
||||
@keyframes xterm-cursor-non-bar-blink {
|
||||
0% { background-color: #fff; }
|
||||
50% { background-color: transparent; }
|
||||
}
|
||||
|
||||
.terminal .composition-view {
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
|
||||
@@ -353,6 +353,7 @@ Terminal.defaults = {
|
||||
termName: 'xterm',
|
||||
geometry: [80, 24],
|
||||
cursorBlink: false,
|
||||
cursorStyle: 'block',
|
||||
visualBell: false,
|
||||
popOnBell: false,
|
||||
scrollback: 1000,
|
||||
@@ -427,6 +428,11 @@ Terminal.prototype.setOption = function(key, value) {
|
||||
this.options[key] = value;
|
||||
switch (key) {
|
||||
case 'cursorBlink': this.element.classList.toggle('xterm-cursor-blink', value); break;
|
||||
case 'cursorStyle':
|
||||
// Style 'block' applies with no class
|
||||
this.element.classList.toggle(`xterm-cursor-style-underline`, value === 'underline');
|
||||
this.element.classList.toggle(`xterm-cursor-style-bar`, value === 'bar');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user