Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
14a0c187
Commit
14a0c187
authored
Feb 26, 2016
by
liuzheng712
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'issue_59_bug_fix' into dev
parents
49e7796d
037a88f0
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
2386 additions
and
295 deletions
+2386
-295
term.js
static/js/term.js
+2386
-295
No files found.
static/js/term.js
View file @
14a0c187
/**
/**
* tty.js - an xterm emulator
* term.js - an xterm emulator
* Christopher Jeffrey (https://github.com/chjj/tty.js)
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
*
*
* Originally forked from (with the author's permission):
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* Copyright (c) 2011 Fabrice Bellard
* (Redistribution or commercial use is prohibited
* without the author's permission.)
*
* The original design remains. The terminal itself
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* has been extended to include xterm CSI codes, among
* other features.
* other features.
*/
*/
;(
function
()
{
;(
function
()
{
...
@@ -42,7 +57,7 @@ var window = this
...
@@ -42,7 +57,7 @@ var window = this
*/
*/
function
EventEmitter
()
{
function
EventEmitter
()
{
this
.
_events
=
{};
this
.
_events
=
this
.
_events
||
{};
}
}
EventEmitter
.
prototype
.
addListener
=
function
(
type
,
listener
)
{
EventEmitter
.
prototype
.
addListener
=
function
(
type
,
listener
)
{
...
@@ -99,6 +114,54 @@ EventEmitter.prototype.listeners = function(type) {
...
@@ -99,6 +114,54 @@ EventEmitter.prototype.listeners = function(type) {
return
this
.
_events
[
type
]
=
this
.
_events
[
type
]
||
[];
return
this
.
_events
[
type
]
=
this
.
_events
[
type
]
||
[];
};
};
/**
* Stream
*/
function
Stream
()
{
EventEmitter
.
call
(
this
);
}
inherits
(
Stream
,
EventEmitter
);
Stream
.
prototype
.
pipe
=
function
(
dest
,
options
)
{
var
src
=
this
,
ondata
,
onerror
,
onend
;
function
unbind
()
{
src
.
removeListener
(
'data'
,
ondata
);
src
.
removeListener
(
'error'
,
onerror
);
src
.
removeListener
(
'end'
,
onend
);
dest
.
removeListener
(
'error'
,
onerror
);
dest
.
removeListener
(
'close'
,
unbind
);
}
src
.
on
(
'data'
,
ondata
=
function
(
data
)
{
dest
.
write
(
data
);
});
src
.
on
(
'error'
,
onerror
=
function
(
err
)
{
unbind
();
if
(
!
this
.
listeners
(
'error'
).
length
)
{
throw
err
;
}
});
src
.
on
(
'end'
,
onend
=
function
()
{
dest
.
end
();
unbind
();
});
dest
.
on
(
'error'
,
onerror
);
dest
.
on
(
'close'
,
unbind
);
dest
.
emit
(
'pipe'
,
src
);
return
dest
;
};
/**
/**
* States
* States
*/
*/
...
@@ -109,33 +172,75 @@ var normal = 0
...
@@ -109,33 +172,75 @@ var normal = 0
,
osc
=
3
,
osc
=
3
,
charset
=
4
,
charset
=
4
,
dcs
=
5
,
dcs
=
5
,
ignore
=
6
;
,
ignore
=
6
,
UDK
=
{
type
:
'udk'
};
/**
/**
* Terminal
* Terminal
*/
*/
function
Terminal
(
cols
,
rows
,
handler
)
{
function
Terminal
(
options
)
{
EventEmitter
.
call
(
this
)
;
var
self
=
this
;
var
options
;
if
(
!
(
this
instanceof
Terminal
))
{
if
(
typeof
cols
===
'object'
)
{
return
new
Terminal
(
arguments
[
0
],
arguments
[
1
],
arguments
[
2
]);
options
=
cols
;
cols
=
options
.
cols
;
rows
=
options
.
rows
;
handler
=
options
.
handler
;
}
}
this
.
_options
=
options
||
{};
this
.
cols
=
cols
||
Terminal
.
geometry
[
0
];
Stream
.
call
(
this
);
this
.
rows
=
rows
||
Terminal
.
geometry
[
1
];
//if (handler) {
if
(
typeof
options
===
'number'
)
{
// this.on('data', handler);
options
=
{
//}
cols
:
arguments
[
0
],
this
.
handler
=
handler
;
rows
:
arguments
[
1
],
if
(
this
.
handler
){
handler
:
arguments
[
2
]
this
.
on
(
'data'
,
this
.
handler
);
};
}
options
=
options
||
{};
each
(
keys
(
Terminal
.
defaults
),
function
(
key
)
{
if
(
options
[
key
]
==
null
)
{
options
[
key
]
=
Terminal
.
options
[
key
];
// Legacy:
if
(
Terminal
[
key
]
!==
Terminal
.
defaults
[
key
])
{
options
[
key
]
=
Terminal
[
key
];
}
}
self
[
key
]
=
options
[
key
];
});
if
(
options
.
colors
.
length
===
8
)
{
options
.
colors
=
options
.
colors
.
concat
(
Terminal
.
_colors
.
slice
(
8
));
}
else
if
(
options
.
colors
.
length
===
16
)
{
options
.
colors
=
options
.
colors
.
concat
(
Terminal
.
_colors
.
slice
(
16
));
}
else
if
(
options
.
colors
.
length
===
10
)
{
options
.
colors
=
options
.
colors
.
slice
(
0
,
-
2
).
concat
(
Terminal
.
_colors
.
slice
(
8
,
-
2
),
options
.
colors
.
slice
(
-
2
));
}
else
if
(
options
.
colors
.
length
===
18
)
{
options
.
colors
=
options
.
colors
.
slice
(
0
,
-
2
).
concat
(
Terminal
.
_colors
.
slice
(
16
,
-
2
),
options
.
colors
.
slice
(
-
2
));
}
this
.
colors
=
options
.
colors
;
this
.
options
=
options
;
// this.context = options.context || window;
// this.document = options.document || document;
this
.
parent
=
options
.
body
||
options
.
parent
||
(
document
?
document
.
getElementsByTagName
(
'body'
)[
0
]
:
null
);
this
.
cols
=
options
.
cols
||
options
.
geometry
[
0
];
this
.
rows
=
options
.
rows
||
options
.
geometry
[
1
];
// Act as though we are a node TTY stream:
this
.
setRawMode
;
this
.
isTTY
=
true
;
this
.
isRaw
=
true
;
this
.
columns
=
this
.
cols
;
this
.
rows
=
this
.
rows
;
if
(
options
.
handler
)
{
this
.
on
(
'data'
,
options
.
handler
);
}
}
this
.
ybase
=
0
;
this
.
ybase
=
0
;
...
@@ -144,7 +249,7 @@ function Terminal(cols, rows, handler) {
...
@@ -144,7 +249,7 @@ function Terminal(cols, rows, handler) {
this
.
y
=
0
;
this
.
y
=
0
;
this
.
cursorState
=
0
;
this
.
cursorState
=
0
;
this
.
cursorHidden
=
false
;
this
.
cursorHidden
=
false
;
this
.
convertEol
=
false
;
this
.
convertEol
;
this
.
state
=
0
;
this
.
state
=
0
;
this
.
queue
=
''
;
this
.
queue
=
''
;
this
.
scrollTop
=
0
;
this
.
scrollTop
=
0
;
...
@@ -152,11 +257,24 @@ function Terminal(cols, rows, handler) {
...
@@ -152,11 +257,24 @@ function Terminal(cols, rows, handler) {
// modes
// modes
this
.
applicationKeypad
=
false
;
this
.
applicationKeypad
=
false
;
this
.
applicationCursor
=
false
;
this
.
originMode
=
false
;
this
.
originMode
=
false
;
this
.
insertMode
=
false
;
this
.
insertMode
=
false
;
this
.
wraparoundMode
=
false
;
this
.
wraparoundMode
=
false
;
this
.
normal
=
null
;
this
.
normal
=
null
;
// select modes
this
.
prefixMode
=
false
;
this
.
selectMode
=
false
;
this
.
visualMode
=
false
;
this
.
searchMode
=
false
;
this
.
searchDown
;
this
.
entry
=
''
;
this
.
entryPrefix
=
'Search: '
;
this
.
_real
;
this
.
_selected
;
this
.
_textarea
;
// charset
// charset
this
.
charset
=
null
;
this
.
charset
=
null
;
this
.
gcharset
=
null
;
this
.
gcharset
=
null
;
...
@@ -188,7 +306,7 @@ function Terminal(cols, rows, handler) {
...
@@ -188,7 +306,7 @@ function Terminal(cols, rows, handler) {
this
.
readable
=
true
;
this
.
readable
=
true
;
this
.
writable
=
true
;
this
.
writable
=
true
;
this
.
defAttr
=
(
257
<<
9
)
|
256
;
this
.
defAttr
=
(
0
<<
18
)
|
(
257
<<
9
)
|
(
256
<<
0
)
;
this
.
curAttr
=
this
.
defAttr
;
this
.
curAttr
=
this
.
defAttr
;
this
.
params
=
[];
this
.
params
=
[];
...
@@ -206,14 +324,14 @@ function Terminal(cols, rows, handler) {
...
@@ -206,14 +324,14 @@ function Terminal(cols, rows, handler) {
this
.
setupStops
();
this
.
setupStops
();
}
}
inherits
(
Terminal
,
EventEmitter
);
inherits
(
Terminal
,
Stream
);
/**
/**
* Colors
* Colors
*/
*/
// Colors 0-15
// Colors 0-15
Terminal
.
c
olors
=
[
Terminal
.
tangoC
olors
=
[
// dark:
// dark:
'#2e3436'
,
'#2e3436'
,
'#cc0000'
,
'#cc0000'
,
...
@@ -234,10 +352,31 @@ Terminal.colors = [
...
@@ -234,10 +352,31 @@ Terminal.colors = [
'#eeeeec'
'#eeeeec'
];
];
// Colors 16-255
Terminal
.
xtermColors
=
[
// dark:
'#000000'
,
// black
'#cd0000'
,
// red3
'#00cd00'
,
// green3
'#cdcd00'
,
// yellow3
'#0000ee'
,
// blue2
'#cd00cd'
,
// magenta3
'#00cdcd'
,
// cyan3
'#e5e5e5'
,
// gray90
// bright:
'#7f7f7f'
,
// gray50
'#ff0000'
,
// red
'#00ff00'
,
// green
'#ffff00'
,
// yellow
'#5c5cff'
,
// rgb:5c/5c/ff
'#ff00ff'
,
// magenta
'#00ffff'
,
// cyan
'#ffffff'
// white
];
// Colors 0-15 + 16-255
// Much thanks to TooTallNate for writing this.
// Much thanks to TooTallNate for writing this.
Terminal
.
colors
=
(
function
()
{
Terminal
.
colors
=
(
function
()
{
var
colors
=
Terminal
.
colors
var
colors
=
Terminal
.
tangoColors
.
slice
()
,
r
=
[
0x00
,
0x5f
,
0x87
,
0xaf
,
0xd7
,
0xff
]
,
r
=
[
0x00
,
0x5f
,
0x87
,
0xaf
,
0xd7
,
0xff
]
,
i
;
,
i
;
...
@@ -267,27 +406,55 @@ Terminal.colors = (function() {
...
@@ -267,27 +406,55 @@ Terminal.colors = (function() {
})();
})();
// Default BG/FG
// Default BG/FG
Terminal
.
defaultColors
=
{
Terminal
.
colors
[
256
]
=
'#000000'
;
bg
:
'#000000'
,
Terminal
.
colors
[
257
]
=
'#f0f0f0'
;
fg
:
'#f0f0f0'
};
Terminal
.
_colors
=
Terminal
.
colors
.
slice
();
Terminal
.
vcolors
=
(
function
()
{
var
out
=
[]
,
colors
=
Terminal
.
colors
,
i
=
0
,
color
;
for
(;
i
<
256
;
i
++
)
{
color
=
parseInt
(
colors
[
i
].
substring
(
1
),
16
);
out
.
push
([
(
color
>>
16
)
&
0xff
,
(
color
>>
8
)
&
0xff
,
color
&
0xff
]);
}
Terminal
.
colors
[
256
]
=
Terminal
.
defaultColors
.
bg
;
return
out
;
Terminal
.
colors
[
257
]
=
Terminal
.
defaultColors
.
fg
;
})()
;
/**
/**
* Options
* Options
*/
*/
Terminal
.
termName
=
'xterm'
;
Terminal
.
defaults
=
{
Terminal
.
geometry
=
[
80
,
30
];
colors
:
Terminal
.
colors
,
Terminal
.
cursorBlink
=
true
;
convertEol
:
false
,
Terminal
.
visualBell
=
false
;
termName
:
'xterm'
,
Terminal
.
popOnBell
=
false
;
geometry
:
[
80
,
24
],
Terminal
.
scrollback
=
1000
;
cursorBlink
:
true
,
Terminal
.
screenKeys
=
false
;
visualBell
:
false
,
Terminal
.
programFeatures
=
false
;
popOnBell
:
false
,
Terminal
.
debug
=
false
;
scrollback
:
1000
,
screenKeys
:
false
,
debug
:
false
,
useStyle
:
false
// programFeatures: false,
// focusKeys: false,
};
Terminal
.
options
=
{};
each
(
keys
(
Terminal
.
defaults
),
function
(
key
)
{
Terminal
[
key
]
=
Terminal
.
defaults
[
key
];
Terminal
.
options
[
key
]
=
Terminal
.
defaults
[
key
];
});
/**
/**
* Focused Terminal
* Focused Terminal
...
@@ -296,67 +463,537 @@ Terminal.debug = false;
...
@@ -296,67 +463,537 @@ Terminal.debug = false;
Terminal
.
focus
=
null
;
Terminal
.
focus
=
null
;
Terminal
.
prototype
.
focus
=
function
()
{
Terminal
.
prototype
.
focus
=
function
()
{
if
(
this
.
_textarea
)
{
this
.
_textarea
.
focus
();
}
if
(
Terminal
.
focus
===
this
)
return
;
if
(
Terminal
.
focus
===
this
)
return
;
if
(
Terminal
.
focus
)
{
if
(
Terminal
.
focus
)
{
Terminal
.
focus
.
cursorState
=
0
;
Terminal
.
focus
.
blur
();
Terminal
.
focus
.
refresh
(
Terminal
.
focus
.
y
,
Terminal
.
focus
.
y
);
if
(
Terminal
.
focus
.
sendFocus
)
Terminal
.
focus
.
send
(
'
\
x1b[O'
);
}
}
Terminal
.
focus
=
this
;
if
(
this
.
sendFocus
)
this
.
send
(
'
\
x1b[I'
);
if
(
this
.
sendFocus
)
this
.
send
(
'
\
x1b[I'
);
this
.
showCursor
();
this
.
showCursor
();
// try {
// this.element.focus();
// } catch (e) {
// ;
// }
// this.emit('focus');
Terminal
.
focus
=
this
;
};
Terminal
.
prototype
.
blur
=
function
()
{
if
(
Terminal
.
focus
!==
this
)
return
;
this
.
cursorState
=
0
;
this
.
refresh
(
this
.
y
,
this
.
y
);
if
(
this
.
sendFocus
)
this
.
send
(
'
\
x1b[O'
);
// try {
// this.element.blur();
// } catch (e) {
// ;
// }
// this.emit('blur');
Terminal
.
focus
=
null
;
};
};
/**
/**
* Global Events for key handling
* Initialize global behavior
*/
Terminal
.
prototype
.
initGlobal
=
function
()
{
var
document
=
this
.
document
;
Terminal
.
_boundDocs
=
Terminal
.
_boundDocs
||
[];
if
(
~
indexOf
(
Terminal
.
_boundDocs
,
document
))
{
return
;
}
Terminal
.
_boundDocs
.
push
(
document
);
Terminal
.
bindPaste
(
document
);
Terminal
.
bindKeys
(
document
);
Terminal
.
bindCopy
(
document
);
if
(
this
.
useStyle
)
{
Terminal
.
insertStyle
(
document
,
this
.
colors
[
256
],
this
.
colors
[
257
]);
}
};
/**
* Bind to paste event
*/
*/
Terminal
.
bindKeys
=
function
()
{
Terminal
.
bindPaste
=
function
(
document
)
{
if
(
Terminal
.
focus
)
return
;
// This seems to work well for ctrl-V and middle-click,
// even without the contentEditable workaround.
var
window
=
document
.
defaultView
;
on
(
window
,
'paste'
,
function
(
ev
)
{
var
term
=
Terminal
.
focus
;
if
(
!
term
)
return
;
if
(
term
.
_textarea
)
return
;
if
(
ev
.
clipboardData
)
{
term
.
send
(
ev
.
clipboardData
.
getData
(
'text/plain'
));
}
else
if
(
term
.
context
.
clipboardData
)
{
term
.
send
(
term
.
context
.
clipboardData
.
getData
(
'Text'
));
}
// Not necessary. Do it anyway for good measure.
term
.
element
.
contentEditable
=
'inherit'
;
return
cancel
(
ev
);
});
};
/**
* Global Events for key handling
*/
// We could put an "if (Terminal.focus)" check
Terminal
.
bindKeys
=
function
(
document
)
{
// here, but it shouldn't be necessary.
// We should only need to check `target === body` below,
// but we can check everything for good measure.
on
(
document
,
'keydown'
,
function
(
ev
)
{
on
(
document
,
'keydown'
,
function
(
ev
)
{
if
(
!
Terminal
.
focus
)
return
;
var
target
=
ev
.
target
||
ev
.
srcElement
;
if
(
!
target
)
return
;
if
(
target
===
Terminal
.
focus
.
element
||
target
===
Terminal
.
focus
.
context
||
target
===
Terminal
.
focus
.
document
||
target
===
Terminal
.
focus
.
body
||
target
===
Terminal
.
focus
.
_textarea
||
target
===
Terminal
.
focus
.
parent
)
{
return
Terminal
.
focus
.
keyDown
(
ev
);
return
Terminal
.
focus
.
keyDown
(
ev
);
}
},
true
);
},
true
);
on
(
document
,
'keypress'
,
function
(
ev
)
{
on
(
document
,
'keypress'
,
function
(
ev
)
{
if
(
!
Terminal
.
focus
)
return
;
var
target
=
ev
.
target
||
ev
.
srcElement
;
if
(
!
target
)
return
;
if
(
target
===
Terminal
.
focus
.
element
||
target
===
Terminal
.
focus
.
context
||
target
===
Terminal
.
focus
.
document
||
target
===
Terminal
.
focus
.
body
||
target
===
Terminal
.
focus
.
_textarea
||
target
===
Terminal
.
focus
.
parent
)
{
return
Terminal
.
focus
.
keyPress
(
ev
);
return
Terminal
.
focus
.
keyPress
(
ev
);
}
},
true
);
},
true
);
// If we click somewhere other than a
// terminal, unfocus the terminal.
on
(
document
,
'mousedown'
,
function
(
ev
)
{
if
(
!
Terminal
.
focus
)
return
;
var
el
=
ev
.
target
||
ev
.
srcElement
;
if
(
!
el
)
return
;
if
(
!
el
.
parentNode
)
return
;
if
(
!
el
.
parentNode
.
parentNode
)
return
;
do
{
if
(
el
===
Terminal
.
focus
.
element
)
return
;
}
while
(
el
=
el
.
parentNode
);
Terminal
.
focus
.
blur
();
});
};
/**
* Copy Selection w/ Ctrl-C (Select Mode)
*/
Terminal
.
bindCopy
=
function
(
document
)
{
var
window
=
document
.
defaultView
;
// if (!('onbeforecopy' in document)) {
// // Copies to *only* the clipboard.
// on(window, 'copy', function fn(ev) {
// var term = Terminal.focus;
// if (!term) return;
// if (!term._selected) return;
// var text = term.grabText(
// term._selected.x1, term._selected.x2,
// term._selected.y1, term._selected.y2);
// term.emit('copy', text);
// ev.clipboardData.setData('text/plain', text);
// });
// return;
// }
// Copies to primary selection *and* clipboard.
// NOTE: This may work better on capture phase,
// or using the `beforecopy` event.
on
(
window
,
'copy'
,
function
(
ev
)
{
var
term
=
Terminal
.
focus
;
if
(
!
term
)
return
;
if
(
!
term
.
_selected
)
return
;
var
textarea
=
term
.
getCopyTextarea
();
var
text
=
term
.
grabText
(
term
.
_selected
.
x1
,
term
.
_selected
.
x2
,
term
.
_selected
.
y1
,
term
.
_selected
.
y2
);
term
.
emit
(
'copy'
,
text
);
textarea
.
focus
();
textarea
.
textContent
=
text
;
textarea
.
value
=
text
;
textarea
.
setSelectionRange
(
0
,
text
.
length
);
setTimeout
(
function
()
{
term
.
element
.
focus
();
term
.
focus
();
},
1
);
});
};
/**
* Fix Mobile
*/
Terminal
.
prototype
.
getTextarea
=
function
(
document
)
{
var
self
=
this
;
var
textarea
=
document
.
createElement
(
'textarea'
);
textarea
.
style
.
position
=
'absolute'
;
textarea
.
style
.
left
=
'-32000px'
;
textarea
.
style
.
top
=
'-32000px'
;
textarea
.
style
.
width
=
'100em'
;
textarea
.
style
.
height
=
'2em'
;
textarea
.
style
.
padding
=
'0'
;
textarea
.
style
.
opacity
=
'0'
;
textarea
.
style
.
color
=
'inherit'
;
textarea
.
style
.
font
=
'inherit'
;
textarea
.
style
.
textIndent
=
'-1em'
;
/* Hide text cursor on IE */
textarea
.
style
.
backgroundColor
=
'transparent'
;
textarea
.
style
.
borderStyle
=
'none'
;
textarea
.
style
.
outlineStyle
=
'none'
;
textarea
.
autocapitalize
=
'none'
;
textarea
.
autocorrect
=
'off'
;
var
onInputTimestamp
;
var
onInput
=
function
(
ev
){
if
(
ev
.
timeStamp
&&
ev
.
timeStamp
===
onInputTimestamp
){
return
;
}
onInputTimestamp
=
ev
.
timeStamp
;
var
value
=
textarea
.
textContent
||
textarea
.
value
;
if
(
typeof
self
.
select
.
startPos
!==
'undefined'
){
self
.
select
=
{};
self
.
clearSelectedText
();
self
.
refresh
(
0
,
self
.
rows
-
1
);
}
if
(
!
self
.
compositionStatus
)
{
textarea
.
value
=
''
;
textarea
.
textContent
=
''
;
self
.
send
(
value
);
}
};
on
(
textarea
,
'compositionstart'
,
function
()
{
textarea
.
style
.
opacity
=
"1.0"
;
textarea
.
style
.
textIndent
=
"0"
;
self
.
compositionStatus
=
true
;
});
on
(
textarea
,
'compositionend'
,
function
(
ev
)
{
textarea
.
style
.
opacity
=
"0.0"
;
textarea
.
style
.
textIndent
=
"-1em"
;
self
.
compositionStatus
=
false
;
setTimeout
(
function
(){
onInput
(
ev
);
// for IE that does not trigger 'input' after the IME composition.
},
1
);
});
on
(
textarea
,
'keydown'
,
function
(){
var
value
=
textarea
.
textContent
||
textarea
.
value
;
});
on
(
textarea
,
'input'
,
onInput
);
if
(
Terminal
.
isAndroid
)
{
on
(
textarea
,
'change'
,
function
()
{
var
value
=
textarea
.
textContent
||
textarea
.
value
;
textarea
.
value
=
''
;
textarea
.
textContent
=
''
;
self
.
send
(
value
+
'
\
r'
);
});
}
return
textarea
;
};
/**
* Insert a default style
*/
Terminal
.
insertStyle
=
function
(
document
,
bg
,
fg
)
{
var
style
=
document
.
getElementById
(
'term-style'
);
if
(
style
)
return
;
var
head
=
document
.
getElementsByTagName
(
'head'
)[
0
];
if
(
!
head
)
return
;
var
style
=
document
.
createElement
(
'style'
);
style
.
id
=
'term-style'
;
// textContent doesn't work well with IE for <style> elements.
style
.
innerHTML
=
''
+
'.terminal {
\
n'
+
' float: left;
\
n'
+
' border: '
+
bg
+
' solid 5px;
\
n'
+
' font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;
\
n'
+
' font-size: 11px;
\
n'
+
' color: '
+
fg
+
';
\
n'
+
' background: '
+
bg
+
';
\
n'
+
'}
\
n'
+
'
\
n'
+
'.terminal-cursor {
\
n'
+
' color: '
+
bg
+
';
\
n'
+
' background: '
+
fg
+
';
\
n'
+
'}
\
n'
;
// var out = '';
// each(Terminal.colors, function(color, i) {
// if (i === 256) {
// out += '\n.term-bg-color-default { background-color: ' + color + '; }';
// }
// if (i === 257) {
// out += '\n.term-fg-color-default { color: ' + color + '; }';
// }
// out += '\n.term-bg-color-' + i + ' { background-color: ' + color + '; }';
// out += '\n.term-fg-color-' + i + ' { color: ' + color + '; }';
// });
// style.innerHTML += out + '\n';
head
.
insertBefore
(
style
,
head
.
firstChild
);
};
};
/**
/**
* Open Terminal
* Open Terminal
*/
*/
Terminal
.
prototype
.
open
=
function
()
{
Terminal
.
prototype
.
open
=
function
(
parent
)
{
var
self
=
this
var
self
=
this
,
i
=
0
,
i
=
0
,
div
;
,
div
;
this
.
element
=
document
.
createElement
(
'div'
);
this
.
parent
=
parent
||
this
.
parent
;
if
(
!
this
.
parent
)
{
throw
new
Error
(
'Terminal requires a parent element.'
);
}
// Grab global elements.
this
.
context
=
this
.
parent
.
ownerDocument
.
defaultView
;
this
.
document
=
this
.
parent
.
ownerDocument
;
this
.
body
=
this
.
document
.
getElementsByTagName
(
'body'
)[
0
];
// Parse user-agent strings.
if
(
this
.
context
.
navigator
&&
this
.
context
.
navigator
.
userAgent
)
{
this
.
isMac
=
!!~
this
.
context
.
navigator
.
userAgent
.
indexOf
(
'Mac'
);
this
.
isIpad
=
!!~
this
.
context
.
navigator
.
userAgent
.
indexOf
(
'iPad'
);
this
.
isIphone
=
!!~
this
.
context
.
navigator
.
userAgent
.
indexOf
(
'iPhone'
);
this
.
isAndroid
=
!!~
this
.
context
.
navigator
.
userAgent
.
indexOf
(
'Android'
);
this
.
isMobile
=
this
.
isIpad
||
this
.
isIphone
||
this
.
isAndroid
;
this
.
isMSIE
=
!!~
this
.
context
.
navigator
.
userAgent
.
indexOf
(
'MSIE'
);
}
// Create our main terminal element.
this
.
element
=
this
.
document
.
createElement
(
'div'
);
this
.
element
.
className
=
'terminal'
;
this
.
element
.
className
=
'terminal'
;
this
.
children
=
[];
this
.
element
.
style
.
outline
=
'none'
;
this
.
element
.
setAttribute
(
'tabindex'
,
0
);
this
.
element
.
setAttribute
(
'spellcheck'
,
'false'
);
this
.
element
.
style
.
backgroundColor
=
this
.
colors
[
256
];
this
.
element
.
style
.
color
=
this
.
colors
[
257
];
// Create the lines for our terminal.
this
.
children
=
[];
for
(;
i
<
this
.
rows
;
i
++
)
{
for
(;
i
<
this
.
rows
;
i
++
)
{
div
=
document
.
createElement
(
'div'
);
div
=
this
.
document
.
createElement
(
'div'
);
this
.
element
.
appendChild
(
div
);
this
.
element
.
appendChild
(
div
);
this
.
children
.
push
(
div
);
this
.
children
.
push
(
div
);
}
}
document
.
body
.
appendChild
(
this
.
element
);
this
.
_textarea
=
this
.
getTextarea
(
this
.
document
);
this
.
element
.
appendChild
(
this
.
_textarea
);
this
.
parent
.
appendChild
(
this
.
element
);
this
.
select
=
{};
// Draw the screen.
this
.
refresh
(
0
,
this
.
rows
-
1
);
this
.
refresh
(
0
,
this
.
rows
-
1
);
Terminal
.
bindKeys
();
var
updateSelect
=
function
(){
var
startPos
=
self
.
select
.
startPos
;
var
endPos
=
self
.
select
.
endPos
;
if
(
endPos
.
y
<
startPos
.
y
||
(
startPos
.
y
==
endPos
.
y
&&
endPos
.
x
<
startPos
.
x
)){
var
tmp
=
startPos
;
startPos
=
endPos
;
endPos
=
tmp
;
}
if
(
self
.
select
.
clicks
===
2
){
var
j
=
i
;
var
isMark
=
function
(
ch
){
var
code
=
ch
.
charCodeAt
(
0
);
return
(
code
<=
0x2f
)
||
(
0x3a
<=
code
&&
code
<=
0x40
)
||
(
0x5b
<=
code
&&
code
<
0x60
)
||
(
0x7b
<=
code
&&
code
<=
0x7f
);
}
while
(
startPos
.
x
>
0
&&
!
isMark
(
self
.
lines
[
startPos
.
y
][
startPos
.
x
-
1
][
1
])){
startPos
.
x
--
;
}
while
(
endPos
.
x
<
self
.
cols
&&
!
isMark
(
self
.
lines
[
endPos
.
y
][
endPos
.
x
][
1
])){
endPos
.
x
++
;
}
}
else
if
(
self
.
select
.
clicks
===
3
){
startPos
.
x
=
0
;
endPos
.
y
++
;
endPos
.
x
=
0
;
}
if
(
startPos
.
x
===
endPos
.
x
&&
startPos
.
y
===
endPos
.
y
){
self
.
clearSelectedText
();
}
else
{
var
x2
=
endPos
.
x
;
var
y2
=
endPos
.
y
;
x2
--
;
if
(
x2
<
0
){
y2
--
;
x2
=
self
.
cols
-
1
;
}
self
.
selectText
(
startPos
.
x
,
x2
,
startPos
.
y
,
y2
);
}
};
var
copySelectToTextarea
=
function
(){
var
textarea
=
self
.
_textarea
;
if
(
textarea
)
{
if
(
self
.
select
.
startPos
.
x
===
self
.
select
.
endPos
.
x
&&
self
.
select
.
startPos
.
y
===
self
.
select
.
endPos
.
y
){
textarea
.
value
=
""
;
textarea
.
select
();
return
;
}
var
x2
=
self
.
select
.
endPos
.
x
;
var
y2
=
self
.
select
.
endPos
.
y
;
x2
--
;
if
(
x2
<
0
){
y2
--
;
x2
=
self
.
cols
-
1
;
}
var
value
=
self
.
grabText
(
self
.
select
.
startPos
.
x
,
x2
,
self
.
select
.
startPos
.
y
,
y2
);
textarea
.
value
=
value
;
textarea
.
select
();
}
};
on
(
this
.
element
,
'mousedown'
,
function
(
ev
)
{
if
(
ev
.
button
===
2
){
var
r
=
self
.
element
.
getBoundingClientRect
();
var
x
=
ev
.
pageX
-
r
.
left
+
self
.
element
.
offsetLeft
;
var
y
=
ev
.
pageY
-
r
.
top
+
self
.
element
.
offsetTop
;
self
.
_textarea
.
style
.
left
=
x
+
'px'
;
self
.
_textarea
.
style
.
top
=
y
+
'px'
;
return
;
}
if
(
ev
.
button
!=
0
){
return
;
}
if
(
navigator
.
userAgent
.
indexOf
(
"Trident"
)){
/* IE does not hold click number as "detail" property. */
if
(
self
.
select
.
timer
){
self
.
select
.
clicks
++
;
clearTimeout
(
self
.
select
.
timer
);
self
.
select
.
timer
=
null
;
}
else
{
self
.
select
.
clicks
=
1
;
}
self
.
select
.
timer
=
setTimeout
(
function
(){
self
.
select
.
timer
=
null
;
},
600
);
}
else
{
self
.
select
.
clicks
=
ev
.
detail
;
}
if
(
!
ev
.
shiftKey
){
self
.
clearSelectedText
();
self
.
select
.
startPos
=
self
.
getCoords
(
ev
);
self
.
select
.
startPos
.
y
+=
self
.
ydisp
;
}
self
.
select
.
endPos
=
self
.
getCoords
(
ev
);
self
.
select
.
endPos
.
y
+=
self
.
ydisp
;
updateSelect
();
copySelectToTextarea
();
self
.
refresh
(
0
,
self
.
rows
-
1
);
self
.
select
.
selecting
=
true
;
});
on
(
this
.
element
,
'mousemove'
,
function
(
ev
)
{
if
(
self
.
select
.
selecting
){
self
.
select
.
endPos
=
self
.
getCoords
(
ev
);
self
.
select
.
endPos
.
y
+=
self
.
ydisp
;
updateSelect
();
self
.
refresh
(
0
,
self
.
rows
-
1
);
}
});
on
(
document
,
'mouseup'
,
function
(
ev
)
{
if
(
ev
.
button
===
2
){
var
r
=
self
.
element
.
getBoundingClientRect
();
var
x
=
ev
.
pageX
-
r
.
left
+
self
.
element
.
offsetLeft
;
var
y
=
ev
.
pageY
-
r
.
top
+
self
.
element
.
offsetTop
;
self
.
_textarea
.
style
.
left
=
x
-
1
+
'px'
;
self
.
_textarea
.
style
.
top
=
y
-
1
+
'px'
;
return
;
}
if
(
self
.
select
.
selecting
){
self
.
select
.
selecting
=
false
;
copySelectToTextarea
();
}
});
if
(
!
(
'useEvents'
in
this
.
options
)
||
this
.
options
.
useEvents
)
{
// Initialize global actions that
// need to be taken on the document.
this
.
initGlobal
();
}
if
(
!
(
'useFocus'
in
this
.
options
)
||
this
.
options
.
useFocus
)
{
// Ensure there is a Terminal.focus.
this
.
focus
();
this
.
focus
();
// Start blinking the cursor.
this
.
startBlink
();
this
.
startBlink
();
// Bind to DOM events related
// to focus and paste behavior.
on
(
this
.
element
,
'focus'
,
function
()
{
self
.
focus
();
});
// This causes slightly funky behavior.
// on(this.element, 'blur', function() {
// self.blur();
// });
on
(
this
.
element
,
'mousedown'
,
function
()
{
on
(
this
.
element
,
'mousedown'
,
function
()
{
self
.
focus
();
self
.
focus
();
});
});
// Clickable paste workaround, using contentEditable.
// This probably shouldn't work,
// This probably shouldn't work,
// ... but it does. Firefox's paste
// ... but it does. Firefox's paste
// event seems to only work for textareas?
// event seems to only work for textareas?
...
@@ -368,7 +1005,7 @@ Terminal.prototype.open = function() {
...
@@ -368,7 +1005,7 @@ Terminal.prototype.open = function() {
:
null
;
:
null
;
// Does IE9 do this?
// Does IE9 do this?
if
(
~
navigator
.
userAgent
.
indexOf
(
'MSIE'
)
)
{
if
(
self
.
isMSIE
)
{
button
=
button
===
1
?
0
:
button
===
4
?
1
:
button
;
button
=
button
===
1
?
0
:
button
===
4
?
1
:
button
;
}
}
...
@@ -379,32 +1016,87 @@ Terminal.prototype.open = function() {
...
@@ -379,32 +1016,87 @@ Terminal.prototype.open = function() {
self
.
element
.
contentEditable
=
'inherit'
;
// 'false';
self
.
element
.
contentEditable
=
'inherit'
;
// 'false';
},
1
);
},
1
);
},
true
);
},
true
);
on
(
this
.
element
,
'paste'
,
function
(
ev
)
{
if
(
ev
.
clipboardData
)
{
self
.
send
(
ev
.
clipboardData
.
getData
(
'text/plain'
));
}
else
if
(
window
.
clipboardData
)
{
self
.
send
(
window
.
clipboardData
.
getData
(
'Text'
));
}
}
// Not necessary. Do it anyway for good measure.
self
.
element
.
contentEditable
=
'inherit'
;
return
cancel
(
ev
);
});
if
(
!
(
'useMouse'
in
this
.
options
)
||
this
.
options
.
useMouse
)
{
// Listen for mouse events and translate
// them into terminal mouse protocols.
this
.
bindMouse
();
this
.
bindMouse
();
}
// this.emit('open');
if
(
!
(
'useFocus'
in
this
.
options
)
||
this
.
options
.
useFocus
)
{
// This can be useful for pasting,
// as well as the iPad fix.
setTimeout
(
function
()
{
self
.
element
.
focus
();
self
.
focus
();
},
100
);
}
// XXX - hack, move this somewhere else.
// Figure out whether boldness affects
// the character width of monospace fonts.
if
(
Terminal
.
brokenBold
==
null
)
{
if
(
Terminal
.
brokenBold
==
null
)
{
Terminal
.
brokenBold
=
isBoldBroken
();
Terminal
.
brokenBold
=
isBoldBroken
(
this
.
document
);
}
}
// sync default bg/fg colors
this
.
emit
(
'open'
);
this
.
element
.
style
.
backgroundColor
=
Terminal
.
defaultColors
.
bg
;
};
this
.
element
.
style
.
color
=
Terminal
.
defaultColors
.
fg
;
//this.emit('open');
Terminal
.
prototype
.
setRawMode
=
function
(
value
)
{
this
.
isRaw
=
!!
value
;
};
};
Terminal
.
prototype
.
getCoords
=
function
(
ev
)
{
var
x
,
y
,
w
,
h
,
el
;
var
self
=
this
;
// ignore browsers without pageX for now
if
(
ev
.
pageX
==
null
)
return
;
x
=
ev
.
pageX
;
y
=
ev
.
pageY
;
el
=
self
.
element
;
x
-=
el
.
clientLeft
;
y
-=
el
.
clientTop
;
// should probably check offsetParent
// but this is more portable
while
(
el
&&
el
!==
self
.
document
.
documentElement
)
{
x
-=
el
.
offsetLeft
;
y
-=
el
.
offsetTop
;
el
=
'offsetParent'
in
el
?
el
.
offsetParent
:
el
.
parentNode
;
}
// convert to cols/rows
w
=
self
.
element
.
clientWidth
;
h
=
self
.
element
.
clientHeight
;
var
cols
=
Math
.
floor
((
x
/
w
)
*
self
.
cols
);
var
rows
=
Math
.
floor
((
y
/
h
)
*
self
.
rows
);
// be sure to avoid sending
// bad positions to the program
if
(
cols
<
0
)
cols
=
0
;
if
(
cols
>
self
.
cols
)
cols
=
self
.
cols
;
if
(
rows
<
0
)
rows
=
0
;
if
(
rows
>
self
.
rows
)
rows
=
self
.
rows
;
// xterm sends raw bytes and
// starts at 32 (SP) for each.
//x += 32;
//y += 32;
return
{
x
:
cols
,
y
:
rows
,
};
}
// XTerm mouse events
// XTerm mouse events
// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
// To better understand these
// To better understand these
...
@@ -418,7 +1110,7 @@ Terminal.prototype.bindMouse = function() {
...
@@ -418,7 +1110,7 @@ Terminal.prototype.bindMouse = function() {
,
self
=
this
,
self
=
this
,
pressed
=
32
;
,
pressed
=
32
;
var
wheelEvent
=
'onmousewheel'
in
window
var
wheelEvent
=
'onmousewheel'
in
this
.
context
?
'mousewheel'
?
'mousewheel'
:
'DOMMouseScroll'
;
:
'DOMMouseScroll'
;
...
@@ -596,7 +1288,7 @@ Terminal.prototype.bindMouse = function() {
...
@@ -596,7 +1288,7 @@ Terminal.prototype.bindMouse = function() {
?
ev
.
which
-
1
?
ev
.
which
-
1
:
null
;
:
null
;
if
(
~
navigator
.
userAgent
.
indexOf
(
'MSIE'
)
)
{
if
(
self
.
isMSIE
)
{
button
=
button
===
1
?
0
:
button
===
4
?
1
:
button
;
button
=
button
===
1
?
0
:
button
===
4
?
1
:
button
;
}
}
break
;
break
;
...
@@ -649,17 +1341,19 @@ Terminal.prototype.bindMouse = function() {
...
@@ -649,17 +1341,19 @@ Terminal.prototype.bindMouse = function() {
// should probably check offsetParent
// should probably check offsetParent
// but this is more portable
// but this is more portable
while
(
el
!==
document
.
documentElement
)
{
while
(
el
&&
el
!==
self
.
document
.
documentElement
)
{
x
-=
el
.
offsetLeft
;
x
-=
el
.
offsetLeft
;
y
-=
el
.
offsetTop
;
y
-=
el
.
offsetTop
;
el
=
el
.
parentNode
;
el
=
'offsetParent'
in
el
?
el
.
offsetParent
:
el
.
parentNode
;
}
}
// convert to cols/rows
// convert to cols/rows
w
=
self
.
element
.
clientWidth
;
w
=
self
.
element
.
clientWidth
;
h
=
self
.
element
.
clientHeight
;
h
=
self
.
element
.
clientHeight
;
x
=
((
x
/
w
)
*
self
.
cols
)
|
0
;
x
=
Math
.
round
((
x
/
w
)
*
self
.
cols
)
;
y
=
((
y
/
h
)
*
self
.
rows
)
|
0
;
y
=
Math
.
round
((
y
/
h
)
*
self
.
rows
)
;
// be sure to avoid sending
// be sure to avoid sending
// bad positions to the program
// bad positions to the program
...
@@ -676,10 +1370,9 @@ Terminal.prototype.bindMouse = function() {
...
@@ -676,10 +1370,9 @@ Terminal.prototype.bindMouse = function() {
return
{
return
{
x
:
x
,
x
:
x
,
y
:
y
,
y
:
y
,
down
:
ev
.
type
===
'mousedown'
,
type
:
ev
.
type
===
wheelEvent
up
:
ev
.
type
===
'mouseup'
,
?
'mousewheel'
wheel
:
ev
.
type
===
wheelEvent
,
:
ev
.
type
move
:
ev
.
type
===
'mousemove'
};
};
}
}
...
@@ -693,20 +1386,22 @@ Terminal.prototype.bindMouse = function() {
...
@@ -693,20 +1386,22 @@ Terminal.prototype.bindMouse = function() {
self
.
focus
();
self
.
focus
();
// fix for odd bug
// fix for odd bug
if
(
self
.
vt200Mouse
)
{
//if (self.vt200Mouse && !self.normalMouse) {
sendButton
({
__proto__
:
ev
,
type
:
'mouseup'
});
// XXX This seems to break certain programs.
return
cancel
(
ev
);
// if (self.vt200Mouse) {
}
// sendButton({ __proto__: ev, type: 'mouseup' });
// return cancel(ev);
// }
// bind events
// bind events
if
(
self
.
normalMouse
)
on
(
document
,
'mousemove'
,
sendMove
);
if
(
self
.
normalMouse
)
on
(
self
.
document
,
'mousemove'
,
sendMove
);
// x10 compatibility mode can't send button releases
// x10 compatibility mode can't send button releases
if
(
!
self
.
x10Mouse
)
{
if
(
!
self
.
x10Mouse
)
{
on
(
document
,
'mouseup'
,
function
up
(
ev
)
{
on
(
self
.
document
,
'mouseup'
,
function
up
(
ev
)
{
sendButton
(
ev
);
sendButton
(
ev
);
if
(
self
.
normalMouse
)
off
(
document
,
'mousemove'
,
sendMove
);
if
(
self
.
normalMouse
)
off
(
self
.
document
,
'mousemove'
,
sendMove
);
off
(
document
,
'mouseup'
,
up
);
off
(
self
.
document
,
'mouseup'
,
up
);
return
cancel
(
ev
);
return
cancel
(
ev
);
});
});
}
}
...
@@ -714,6 +1409,10 @@ Terminal.prototype.bindMouse = function() {
...
@@ -714,6 +1409,10 @@ Terminal.prototype.bindMouse = function() {
return
cancel
(
ev
);
return
cancel
(
ev
);
});
});
//if (self.normalMouse) {
// on(self.document, 'mousemove', sendMove);
//}
on
(
el
,
wheelEvent
,
function
(
ev
)
{
on
(
el
,
wheelEvent
,
function
(
ev
)
{
if
(
!
self
.
mouseEvents
)
return
;
if
(
!
self
.
mouseEvents
)
return
;
if
(
self
.
x10Mouse
if
(
self
.
x10Mouse
...
@@ -741,13 +1440,35 @@ Terminal.prototype.bindMouse = function() {
...
@@ -741,13 +1440,35 @@ Terminal.prototype.bindMouse = function() {
* Destroy Terminal
* Destroy Terminal
*/
*/
Terminal
.
prototype
.
close
=
Terminal
.
prototype
.
destroySoon
=
Terminal
.
prototype
.
destroy
=
function
()
{
Terminal
.
prototype
.
destroy
=
function
()
{
if
(
this
.
destroyed
)
{
return
;
}
if
(
this
.
_blink
)
{
clearInterval
(
this
.
_blink
);
delete
this
.
_blink
;
}
this
.
readable
=
false
;
this
.
readable
=
false
;
this
.
writable
=
false
;
this
.
writable
=
false
;
this
.
destroyed
=
true
;
this
.
_events
=
{};
this
.
_events
=
{};
this
.
handler
=
function
()
{};
this
.
handler
=
function
()
{};
this
.
write
=
function
()
{};
this
.
write
=
function
()
{};
//this.emit('close');
this
.
end
=
function
()
{};
if
(
this
.
element
.
parentNode
)
{
this
.
element
.
parentNode
.
removeChild
(
this
.
element
);
}
this
.
emit
(
'end'
);
this
.
emit
(
'close'
);
this
.
emit
(
'finish'
);
this
.
emit
(
'destroy'
);
};
};
/**
/**
...
@@ -762,7 +1483,7 @@ Terminal.prototype.destroy = function() {
...
@@ -762,7 +1483,7 @@ Terminal.prototype.destroy = function() {
// Next 9 bits: background color (0-511).
// Next 9 bits: background color (0-511).
// Next 9 bits: foreground color (0-511).
// Next 9 bits: foreground color (0-511).
// Next 14 bits: a mask for misc. flags:
// Next 14 bits: a mask for misc. flags:
// 1=bold, 2=underline, 4=
invers
e
// 1=bold, 2=underline, 4=
blink, 8=inverse, 16=invisibl
e
Terminal
.
prototype
.
refresh
=
function
(
start
,
end
)
{
Terminal
.
prototype
.
refresh
=
function
(
start
,
end
)
{
var
x
var
x
...
@@ -774,13 +1495,18 @@ Terminal.prototype.refresh = function(start, end) {
...
@@ -774,13 +1495,18 @@ Terminal.prototype.refresh = function(start, end) {
,
width
,
width
,
data
,
data
,
attr
,
attr
,
fgColor
,
bg
,
bgColor
,
fg
,
flags
,
flags
,
row
,
row
,
parent
;
,
parent
;
var
characterWidth
=
this
.
element
.
clientWidth
/
this
.
cols
;
var
characterHeight
=
this
.
element
.
clientHeight
/
this
.
rows
;
var
focused
;
if
(
end
-
start
>=
this
.
rows
/
2
)
{
if
(
end
-
start
>=
this
.
rows
/
2
)
{
focused
=
(
Terminal
.
focus
==
this
);
parent
=
this
.
element
.
parentNode
;
parent
=
this
.
element
.
parentNode
;
if
(
parent
)
parent
.
removeChild
(
this
.
element
);
if
(
parent
)
parent
.
removeChild
(
this
.
element
);
}
}
...
@@ -788,6 +1514,11 @@ Terminal.prototype.refresh = function(start, end) {
...
@@ -788,6 +1514,11 @@ Terminal.prototype.refresh = function(start, end) {
width
=
this
.
cols
;
width
=
this
.
cols
;
y
=
start
;
y
=
start
;
if
(
end
>=
this
.
lines
.
length
)
{
this
.
log
(
'`end` is too large. Most likely a bad CSR.'
);
end
=
this
.
lines
.
length
-
1
;
}
for
(;
y
<=
end
;
y
++
)
{
for
(;
y
<=
end
;
y
++
)
{
row
=
y
+
this
.
ydisp
;
row
=
y
+
this
.
ydisp
;
...
@@ -796,7 +1527,7 @@ Terminal.prototype.refresh = function(start, end) {
...
@@ -796,7 +1527,7 @@ Terminal.prototype.refresh = function(start, end) {
if
(
y
===
this
.
y
if
(
y
===
this
.
y
&&
this
.
cursorState
&&
this
.
cursorState
&&
this
.
ydisp
===
this
.
ybase
&&
(
this
.
ydisp
===
this
.
ybase
||
this
.
selectMode
)
&&
!
this
.
cursorHidden
)
{
&&
!
this
.
cursorHidden
)
{
x
=
this
.
x
;
x
=
this
.
x
;
}
else
{
}
else
{
...
@@ -818,35 +1549,67 @@ Terminal.prototype.refresh = function(start, end) {
...
@@ -818,35 +1549,67 @@ Terminal.prototype.refresh = function(start, end) {
}
}
if
(
data
!==
this
.
defAttr
)
{
if
(
data
!==
this
.
defAttr
)
{
if
(
data
===
-
1
)
{
if
(
data
===
-
1
)
{
out
+=
'<span class="reverse-video">'
;
out
+=
'<span class="reverse-video
terminal-cursor
">'
;
}
else
{
}
else
{
out
+=
'<span style="'
;
out
+=
'<span style="'
;
bg
Color
=
data
&
0x1ff
;
bg
=
data
&
0x1ff
;
fg
Color
=
(
data
>>
9
)
&
0x1ff
;
fg
=
(
data
>>
9
)
&
0x1ff
;
flags
=
data
>>
18
;
flags
=
data
>>
18
;
// bold
if
(
flags
&
1
)
{
if
(
flags
&
1
)
{
if
(
!
Terminal
.
brokenBold
)
{
if
(
!
Terminal
.
brokenBold
)
{
out
+=
'font-weight:bold;'
;
out
+=
'font-weight:bold;'
;
}
}
//
s
ee: XTerm*boldColors
//
S
ee: XTerm*boldColors
if
(
fg
Color
<
8
)
fgColor
+=
8
;
if
(
fg
<
8
)
fg
+=
8
;
}
}
// underline
if
(
flags
&
2
)
{
if
(
flags
&
2
)
{
out
+=
'text-decoration:underline;'
;
out
+=
'text-decoration:underline;'
;
}
}
if
(
bgColor
!==
256
)
{
// blink
if
(
flags
&
4
)
{
if
(
flags
&
2
)
{
out
=
out
.
slice
(
0
,
-
1
);
out
+=
' blink;'
;
}
else
{
out
+=
'text-decoration:blink;'
;
}
}
// inverse
if
(
flags
&
8
)
{
bg
=
(
data
>>
9
)
&
0x1ff
;
fg
=
data
&
0x1ff
;
// Should inverse just be before the
// above boldColors effect instead?
if
((
flags
&
1
)
&&
fg
<
8
)
fg
+=
8
;
}
// invisible
if
(
flags
&
16
)
{
out
+=
'visibility:hidden;'
;
}
// out += '" class="'
// + 'term-bg-color-' + bg
// + ' '
// + 'term-fg-color-' + fg
// + '">';
if
(
bg
!==
256
)
{
out
+=
'background-color:'
out
+=
'background-color:'
+
Terminal
.
colors
[
bgColor
]
+
this
.
colors
[
bg
]
+
';'
;
+
';'
;
}
}
if
(
fg
Color
!==
257
)
{
if
(
fg
!==
257
)
{
out
+=
'color:'
out
+=
'color:'
+
Terminal
.
colors
[
fgColor
]
+
this
.
colors
[
fg
]
+
';'
;
+
';'
;
}
}
...
@@ -868,9 +1631,14 @@ Terminal.prototype.refresh = function(start, end) {
...
@@ -868,9 +1631,14 @@ Terminal.prototype.refresh = function(start, end) {
default
:
default
:
if
(
ch
<=
' '
)
{
if
(
ch
<=
' '
)
{
out
+=
' '
;
out
+=
' '
;
}
else
{
if
(
isWide
(
ch
))
{
i
++
;
out
+=
'<span style="display:inline-block; width:'
+
characterWidth
*
2
+
'px; height:'
+
characterHeight
+
'px; line-height:'
+
characterHeight
+
'px;">'
+
ch
+
'</span>'
;
}
else
{
}
else
{
out
+=
ch
;
out
+=
ch
;
}
}
}
break
;
break
;
}
}
...
@@ -884,10 +1652,26 @@ Terminal.prototype.refresh = function(start, end) {
...
@@ -884,10 +1652,26 @@ Terminal.prototype.refresh = function(start, end) {
this
.
children
[
y
].
innerHTML
=
out
;
this
.
children
[
y
].
innerHTML
=
out
;
}
}
if
(
parent
)
parent
.
appendChild
(
this
.
element
);
if
(
parent
)
{
parent
.
appendChild
(
this
.
element
);
if
(
focused
)
{
this
.
focus
();
}
}
if
(
this
.
_textarea
)
{
var
cursorElement
=
this
.
element
.
querySelector
(
'.terminal-cursor'
);
if
(
cursorElement
){
var
cursor_x
=
cursorElement
.
offsetLeft
;
var
cursor_y
=
cursorElement
.
offsetTop
;
this
.
_textarea
.
style
.
left
=
cursor_x
+
'px'
;
this
.
_textarea
.
style
.
top
=
cursor_y
+
'px'
;
}
}
};
};
Terminal
.
prototype
.
cursorBlink
=
function
()
{
Terminal
.
prototype
.
_
cursorBlink
=
function
()
{
if
(
Terminal
.
focus
!==
this
)
return
;
if
(
Terminal
.
focus
!==
this
)
return
;
this
.
cursorState
^=
1
;
this
.
cursorState
^=
1
;
this
.
refresh
(
this
.
y
,
this
.
y
);
this
.
refresh
(
this
.
y
,
this
.
y
);
...
@@ -904,16 +1688,16 @@ Terminal.prototype.showCursor = function() {
...
@@ -904,16 +1688,16 @@ Terminal.prototype.showCursor = function() {
};
};
Terminal
.
prototype
.
startBlink
=
function
()
{
Terminal
.
prototype
.
startBlink
=
function
()
{
if
(
!
Terminal
.
cursorBlink
)
return
;
if
(
!
this
.
cursorBlink
)
return
;
var
self
=
this
;
var
self
=
this
;
this
.
_blinker
=
function
()
{
this
.
_blinker
=
function
()
{
self
.
cursorBlink
();
self
.
_
cursorBlink
();
};
};
this
.
_blink
=
setInterval
(
this
.
_blinker
,
500
);
this
.
_blink
=
setInterval
(
this
.
_blinker
,
500
);
};
};
Terminal
.
prototype
.
refreshBlink
=
function
()
{
Terminal
.
prototype
.
refreshBlink
=
function
()
{
if
(
!
Terminal
.
cursorB
link
)
return
;
if
(
!
this
.
cursorBlink
||
!
this
.
_b
link
)
return
;
clearInterval
(
this
.
_blink
);
clearInterval
(
this
.
_blink
);
this
.
_blink
=
setInterval
(
this
.
_blinker
,
500
);
this
.
_blink
=
setInterval
(
this
.
_blinker
,
500
);
};
};
...
@@ -921,7 +1705,7 @@ Terminal.prototype.refreshBlink = function() {
...
@@ -921,7 +1705,7 @@ Terminal.prototype.refreshBlink = function() {
Terminal
.
prototype
.
scroll
=
function
()
{
Terminal
.
prototype
.
scroll
=
function
()
{
var
row
;
var
row
;
if
(
++
this
.
ybase
===
Terminal
.
scrollback
)
{
if
(
++
this
.
ybase
===
this
.
scrollback
)
{
this
.
ybase
=
this
.
ybase
/
2
|
0
;
this
.
ybase
=
this
.
ybase
/
2
|
0
;
this
.
lines
=
this
.
lines
.
slice
(
-
(
this
.
ybase
+
this
.
rows
)
+
1
);
this
.
lines
=
this
.
lines
.
slice
(
-
(
this
.
ybase
+
this
.
rows
)
+
1
);
}
}
...
@@ -973,6 +1757,7 @@ Terminal.prototype.scrollDisp = function(disp) {
...
@@ -973,6 +1757,7 @@ Terminal.prototype.scrollDisp = function(disp) {
Terminal
.
prototype
.
write
=
function
(
data
)
{
Terminal
.
prototype
.
write
=
function
(
data
)
{
var
l
=
data
.
length
var
l
=
data
.
length
,
i
=
0
,
i
=
0
,
j
,
cs
,
cs
,
ch
;
,
ch
;
...
@@ -986,13 +1771,14 @@ Terminal.prototype.write = function(data) {
...
@@ -986,13 +1771,14 @@ Terminal.prototype.write = function(data) {
// this.log(JSON.stringify(data.replace(/\x1b/g, '^[')));
// this.log(JSON.stringify(data.replace(/\x1b/g, '^[')));
for
(;
i
<
l
;
i
++
)
{
for
(;
i
<
l
;
i
++
,
this
.
lch
=
ch
)
{
ch
=
data
[
i
];
ch
=
data
[
i
];
switch
(
this
.
state
)
{
switch
(
this
.
state
)
{
case
normal
:
case
normal
:
switch
(
ch
)
{
switch
(
ch
)
{
// '\0'
// '\0'
// case '\0':
// case '\0':
// case '\200':
// break;
// break;
// '\a'
// '\a'
...
@@ -1007,6 +1793,9 @@ Terminal.prototype.write = function(data) {
...
@@ -1007,6 +1793,9 @@ Terminal.prototype.write = function(data) {
if
(
this
.
convertEol
)
{
if
(
this
.
convertEol
)
{
this
.
x
=
0
;
this
.
x
=
0
;
}
}
// TODO: Implement eat_newline_glitch.
// if (this.realX >= this.cols) break;
// this.realX = 0;
this
.
y
++
;
this
.
y
++
;
if
(
this
.
y
>
this
.
scrollBottom
)
{
if
(
this
.
y
>
this
.
scrollBottom
)
{
this
.
y
--
;
this
.
y
--
;
...
@@ -1052,6 +1841,7 @@ Terminal.prototype.write = function(data) {
...
@@ -1052,6 +1841,7 @@ Terminal.prototype.write = function(data) {
if
(
this
.
charset
&&
this
.
charset
[
ch
])
{
if
(
this
.
charset
&&
this
.
charset
[
ch
])
{
ch
=
this
.
charset
[
ch
];
ch
=
this
.
charset
[
ch
];
}
}
if
(
this
.
x
>=
this
.
cols
)
{
if
(
this
.
x
>=
this
.
cols
)
{
this
.
x
=
0
;
this
.
x
=
0
;
this
.
y
++
;
this
.
y
++
;
...
@@ -1060,9 +1850,20 @@ Terminal.prototype.write = function(data) {
...
@@ -1060,9 +1850,20 @@ Terminal.prototype.write = function(data) {
this
.
scroll
();
this
.
scroll
();
}
}
}
}
this
.
lines
[
this
.
y
+
this
.
ybase
][
this
.
x
]
=
[
this
.
curAttr
,
ch
];
this
.
lines
[
this
.
y
+
this
.
ybase
][
this
.
x
]
=
[
this
.
curAttr
,
ch
];
this
.
x
++
;
this
.
x
++
;
this
.
updateRange
(
this
.
y
);
this
.
updateRange
(
this
.
y
);
if
(
isWide
(
ch
))
{
j
=
this
.
y
+
this
.
ybase
;
if
(
this
.
cols
<
2
||
this
.
x
>=
this
.
cols
)
{
this
.
lines
[
j
][
this
.
x
-
1
]
=
[
this
.
curAttr
,
' '
];
break
;
}
this
.
lines
[
j
][
this
.
x
]
=
[
this
.
curAttr
,
' '
];
this
.
x
++
;
}
}
}
break
;
break
;
}
}
...
@@ -1086,7 +1887,8 @@ Terminal.prototype.write = function(data) {
...
@@ -1086,7 +1887,8 @@ Terminal.prototype.write = function(data) {
// ESC P Device Control String ( DCS is 0x90).
// ESC P Device Control String ( DCS is 0x90).
case
'P'
:
case
'P'
:
this
.
params
=
[];
this
.
params
=
[];
this
.
currentParam
=
0
;
this
.
prefix
=
''
;
this
.
currentParam
=
''
;
this
.
state
=
dcs
;
this
.
state
=
dcs
;
break
;
break
;
...
@@ -1309,8 +2111,14 @@ Terminal.prototype.write = function(data) {
...
@@ -1309,8 +2111,14 @@ Terminal.prototype.write = function(data) {
// OSC Ps ; Pt ST
// OSC Ps ; Pt ST
// OSC Ps ; Pt BEL
// OSC Ps ; Pt BEL
// Set Text Parameters.
// Set Text Parameters.
if
(
ch
===
'
\
x1b'
||
ch
===
'
\
x07'
)
{
if
((
this
.
lch
===
'
\
x1b'
&&
ch
===
'
\
\'
) || ch === '
\
x07
') {
if
(
ch
===
'
\
x1b'
)
i
++
;
if (this.lch === '
\
x1b
') {
if (typeof this.currentParam === '
string
') {
this.currentParam = this.currentParam.slice(0, -1);
} else if (typeof this.currentParam == '
number
') {
this.currentParam = (this.currentParam - ('
\
x1b
'.charCodeAt(0) - 48)) / 10;
}
}
this.params.push(this.currentParam);
this.params.push(this.currentParam);
...
@@ -1457,12 +2265,16 @@ Terminal.prototype.write = function(data) {
...
@@ -1457,12 +2265,16 @@ Terminal.prototype.write = function(data) {
// CSI Pm m Character Attributes (SGR).
// CSI Pm m Character Attributes (SGR).
case
'm'
:
case
'm'
:
if
(
!
this
.
prefix
)
{
this
.
charAttributes
(
this
.
params
);
this
.
charAttributes
(
this
.
params
);
}
break
;
break
;
// CSI Ps n Device Status Report (DSR).
// CSI Ps n Device Status Report (DSR).
case
'n'
:
case
'n'
:
if
(
!
this
.
prefix
)
{
this
.
deviceStatus
(
this
.
params
);
this
.
deviceStatus
(
this
.
params
);
}
break
;
break
;
/**
/**
...
@@ -1838,94 +2650,158 @@ Terminal.prototype.write = function(data) {
...
@@ -1838,94 +2650,158 @@ Terminal.prototype.write = function(data) {
break
;
break
;
case
dcs
:
case
dcs
:
if
(
ch
===
'
\
x1b'
||
ch
===
'
\
x07'
)
{
if
((
this
.
lch
===
'
\
x1b'
&&
ch
===
'
\
\'
) || ch === '
\
x07
') {
if
(
ch
===
'
\
x1b'
)
i
++
;
// Workarounds:
if (this.prefix === '
tmux
;
\
x1b
') {
// `DCS tmux; Pt ST` may contain a Pt with an ST
// XXX Does tmux work this way?
// if (this.lch === '
\
x1b
' & data[i + 1] === '
\
x1b
' && data[i + 2] === '
\\
') {
// this.currentParam += ch;
// continue;
// }
// Tmux only accepts ST, not BEL:
if (ch === '
\
x07
') {
this.currentParam += ch;
continue;
}
}
if (this.lch === '
\
x1b
') {
if (typeof this.currentParam === '
string
') {
this.currentParam = this.currentParam.slice(0, -1);
} else if (typeof this.currentParam == '
number
') {
this.currentParam = (this.currentParam - ('
\
x1b
'.charCodeAt(0) - 48)) / 10;
}
}
this.params.push(this.currentParam);
var pt = this.params[this.params.length - 1];
switch (this.prefix) {
switch (this.prefix) {
// User-Defined Keys (DECUDK).
// User-Defined Keys (DECUDK).
case
''
:
// DCS Ps; Ps| Pt ST
case UDK:
this.emit('
udk
', {
clearAll: this.params[0] === 0,
eraseBelow: this.params[0] === 1,
lockKeys: this.params[1] === 0,
dontLockKeys: this.params[1] === 1,
keyList: (this.params[2] + '').split('
;
').map(function(part) {
part = part.split('
/
');
return {
keyCode: part[0],
hexKeyValue: part[1]
};
})
});
break;
break;
// Request Status String (DECRQSS).
// Request Status String (DECRQSS).
// DCS $ q Pt ST
// test: echo -e '
\
eP$q
"p
\
e
\\
'
// test: echo -e '
\
eP$q
"p
\
e
\\
'
case '$q':
case '$q':
var
pt
=
this
.
currentParam
var valid = 0;
,
valid
=
false
;
switch (pt) {
switch (pt) {
// DECSCA
// DECSCA
// CSI Ps "
q
case
'"q'
:
case
'"q'
:
pt
=
'0"q'
;
pt
=
'0"q'
;
valid
=
1
;
break
;
break
;
// DECSCL
// DECSCL
// CSI Ps ; Ps " p
case
'"p'
:
case
'"p'
:
pt
=
'61"p'
;
pt
=
'61;0"p'
;
valid
=
1
;
break
;
break
;
// DECSTBM
// DECSTBM
// CSI Ps ; Ps r
case
'r'
:
case
'r'
:
pt
=
''
pt
=
''
+
(
this
.
scrollTop
+
1
)
+
(
this
.
scrollTop
+
1
)
+
';'
+
';'
+
(
this
.
scrollBottom
+
1
)
+
(
this
.
scrollBottom
+
1
)
+
'r'
;
+
'r'
;
valid
=
1
;
break
;
break
;
// SGR
// SGR
// CSI Pm m
case
'm'
:
case
'm'
:
pt
=
'0m'
;
// TODO: Parse this.curAttr here.
// pt = '0m';
// valid = 1;
valid
=
0
;
// Not implemented.
break
;
break
;
default
:
default
:
this
.
error
(
'Unknown DCS Pt: %s.'
,
pt
);
this
.
error
(
'Unknown DCS Pt: %s.'
,
pt
);
pt
=
''
;
valid
=
0
;
// unimplemented
break
;
break
;
}
}
this
.
send
(
'
\
x1bP'
+
+
valid
+
'$r'
+
pt
+
'
\
x1b
\
\'
);
this
.
send
(
'
\
x1bP'
+
valid
+
'$r'
+
pt
+
'
\
x1b
\
\'
);
break;
break;
// Set Termcap/Terminfo Data (xterm, experimental).
// Set Termcap/Terminfo Data (xterm, experimental).
// DCS + p Pt ST
case '
+
p
':
case '
+
p
':
this.emit('
set
terminfo
', {
name: this.params[0]
});
break;
break;
// Request Termcap/Terminfo String (xterm, experimental)
// Request Termcap/Terminfo String (xterm, experimental)
// Regular xterm does not even respond to this sequence.
// Regular xterm does not even respond to this sequence.
// This can cause a small glitch in vim.
// This can cause a small glitch in vim.
// DCS + q Pt ST
// test: echo -ne '
\
eP
+
q6b64
\
e
\\
'
// test: echo -ne '
\
eP
+
q6b64
\
e
\\
'
case '
+
q
':
case '
+
q
':
var pt = this.currentParam
var valid = false;
, valid = false;
this.send('
\
x1bP
' + +valid + '
+
r
' + pt + '
\
x1b
\\
');
this.send('
\
x1bP
' + +valid + '
+
r
' + pt + '
\
x1b
\\
');
break;
break;
// Implement tmux sequence forwarding is
// someone uses term.js for a multiplexer.
// DCS tmux; ESC Pt ST
case '
tmux
;
\
x1b
':
this.emit('
passthrough
', pt);
break;
default:
default:
this.error('
Unknown
DCS
prefix
:
%
s
.
',
this.prefix
);
this.error('
Unknown
DCS
prefix
:
%
s
.
',
pt
);
break;
break;
}
}
this.currentParam = 0;
this.currentParam = 0;
this.prefix = '';
this.prefix = '';
this.state = normal;
this.state = normal;
} else if (!this.currentParam) {
if (!this.prefix && ch !== '
$
' && ch !== '
+
') {
this.currentParam = ch;
} else if (this.prefix.length === 2) {
this.currentParam = ch;
} else {
this.prefix += ch;
}
} else {
} else {
this.currentParam += ch;
this.currentParam += ch;
if (!this.prefix) {
if (/^
\
d*;
\
d*
\
|/.test(this.currentParam)) {
this.prefix = UDK;
this.params = this.currentParam.split(/[;|]/).map(function(n) {
if (!n.length) return 0;
return +n;
}).slice(0, -1);
this.currentParam = '';
} else if (/^[$+][a-zA-Z]/.test(this.currentParam)
|| /^
\
w+;
\
x1b/.test(this.currentParam)) {
this.prefix = this.currentParam;
this.currentParam = '';
}
}
}
}
break;
break;
case ignore:
case ignore:
// For PM and APC.
// For PM and APC.
if (ch === '
\
x1b
' || ch === '
\
x07
') {
if ((this.lch === '
\
x1b
' && ch === '
\\
') || ch === '
\
x07
') {
if (ch === '
\
x1b
') i++;
this.state = normal;
this.state = normal;
}
}
break;
break;
...
@@ -1934,18 +2810,44 @@ Terminal.prototype.write = function(data) {
...
@@ -1934,18 +2810,44 @@ Terminal.prototype.write = function(data) {
this.updateRange(this.y);
this.updateRange(this.y);
this.refresh(this.refreshStart, this.refreshEnd);
this.refresh(this.refreshStart, this.refreshEnd);
return true;
};
};
Terminal.prototype.writeln = function(data) {
Terminal.prototype.writeln = function(data) {
this.write(data + '
\
r
\
n
');
return this.write(data + '
\
r
\
n
');
};
Terminal.prototype.end = function(data) {
var ret = true;
if (data) {
ret = this.write(data);
}
this.destroySoon();
return ret;
};
Terminal.prototype.resume = function() {
;
};
Terminal.prototype.pause = function() {
;
};
};
// Key Resources:
// https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
Terminal.prototype.keyDown = function(ev) {
Terminal.prototype.keyDown = function(ev) {
var key;
var self = this
, key;
switch (ev.keyCode) {
switch (ev.keyCode) {
// backspace
// backspace
case 8:
case 8:
if (ev.altKey) {
key = '
\
x17
';
break;
}
if (ev.shiftKey) {
if (ev.shiftKey) {
key = '
\
x08
'; // ^H
key = '
\
x08
'; // ^H
break;
break;
...
@@ -1970,24 +2872,32 @@ Terminal.prototype.keyDown = function(ev) {
...
@@ -1970,24 +2872,32 @@ Terminal.prototype.keyDown = function(ev) {
break;
break;
// left-arrow
// left-arrow
case 37:
case 37:
if (this.application
Keypad
) {
if (this.application
Cursor
) {
key = '
\
x1bOD
'; // SS3 as ^[O for 7-bit
key = '
\
x1bOD
'; // SS3 as ^[O for 7-bit
//key = '
\
x8fD
'; // SS3 as 0x8f for 8-bit
//key = '
\
x8fD
'; // SS3 as 0x8f for 8-bit
break;
break;
}
}
if (ev.ctrlKey) {
key = '
\
x1b
[
5
D
';
break;
}
key = '
\
x1b
[
D
';
key = '
\
x1b
[
D
';
break;
break;
// right-arrow
// right-arrow
case 39:
case 39:
if (this.application
Keypad
) {
if (this.application
Cursor
) {
key = '
\
x1bOC
';
key = '
\
x1bOC
';
break;
break;
}
}
if (ev.ctrlKey) {
key = '
\
x1b
[
5
C
';
break;
}
key = '
\
x1b
[
C
';
key = '
\
x1b
[
C
';
break;
break;
// up-arrow
// up-arrow
case 38:
case 38:
if (this.application
Keypad
) {
if (this.application
Cursor
) {
key = '
\
x1bOA
';
key = '
\
x1bOA
';
break;
break;
}
}
...
@@ -2000,7 +2910,7 @@ Terminal.prototype.keyDown = function(ev) {
...
@@ -2000,7 +2910,7 @@ Terminal.prototype.keyDown = function(ev) {
break;
break;
// down-arrow
// down-arrow
case 40:
case 40:
if (this.application
Keypad
) {
if (this.application
Cursor
) {
key = '
\
x1bOB
';
key = '
\
x1bOB
';
break;
break;
}
}
...
@@ -2105,6 +3015,27 @@ Terminal.prototype.keyDown = function(ev) {
...
@@ -2105,6 +3015,27 @@ Terminal.prototype.keyDown = function(ev) {
// a-z and space
// a-z and space
if (ev.ctrlKey) {
if (ev.ctrlKey) {
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
// Ctrl-A
if (this.screenKeys) {
if (!this.prefixMode && !this.selectMode && ev.keyCode === 65) {
this.enterPrefix();
return cancel(ev);
}
}
// Ctrl-V
if (this.prefixMode && ev.keyCode === 86) {
this.leavePrefix();
return;
}
// Ctrl-C
if ((this.prefixMode || this.selectMode) && ev.keyCode === 67) {
if (this.visualMode) {
setTimeout(function() {
self.leaveVisual();
}, 1);
}
return;
}
key = String.fromCharCode(ev.keyCode - 64);
key = String.fromCharCode(ev.keyCode - 64);
} else if (ev.keyCode === 32) {
} else if (ev.keyCode === 32) {
// NUL
// NUL
...
@@ -2122,7 +3053,7 @@ Terminal.prototype.keyDown = function(ev) {
...
@@ -2122,7 +3053,7 @@ Terminal.prototype.keyDown = function(ev) {
// ^] - group sep
// ^] - group sep
key = String.fromCharCode(29);
key = String.fromCharCode(29);
}
}
} else if (
(!isMac && ev.altKey) || (isMac && ev.metaKey)
) {
} else if (
ev.altKey
) {
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
key = '
\
x1b
' + String.fromCharCode(ev.keyCode + 32);
key = '
\
x1b
' + String.fromCharCode(ev.keyCode + 32);
} else if (ev.keyCode === 192) {
} else if (ev.keyCode === 192) {
...
@@ -2134,18 +3065,25 @@ Terminal.prototype.keyDown = function(ev) {
...
@@ -2134,18 +3065,25 @@ Terminal.prototype.keyDown = function(ev) {
break;
break;
}
}
this.emit('keydown', ev);
if (!key) return true;
if (this.prefixMode) {
this.leavePrefix();
return cancel(ev);
}
if (this.selectMode) {
this.keySelect(ev, key);
return cancel(ev);
}
if (key) {
this.emit('keydown', ev);
this.emit('key', key, ev);
this.emit('key', key, ev);
this.showCursor();
this.showCursor();
this.handler(key);
this.handler(key);
return cancel(ev);
return cancel(ev);
}
return true;
};
};
Terminal.prototype.setgLevel = function(g) {
Terminal.prototype.setgLevel = function(g) {
...
@@ -2162,6 +3100,9 @@ Terminal.prototype.setgCharset = function(g, charset) {
...
@@ -2162,6 +3100,9 @@ Terminal.prototype.setgCharset = function(g, charset) {
Terminal.prototype.keyPress = function(ev) {
Terminal.prototype.keyPress = function(ev) {
var key;
var key;
if (this._textarea) {
return;
}
cancel(ev);
cancel(ev);
...
@@ -2179,6 +3120,17 @@ Terminal.prototype.keyPress = function(ev) {
...
@@ -2179,6 +3120,17 @@ Terminal.prototype.keyPress = function(ev) {
key = String.fromCharCode(key);
key = String.fromCharCode(key);
if (this.prefixMode) {
this.leavePrefix();
this.keyPrefix(ev, key);
return false;
}
if (this.selectMode) {
this.keySelect(ev, key);
return false;
}
this.emit('keypress', key, ev);
this.emit('keypress', key, ev);
this.emit('key', key, ev);
this.emit('key', key, ev);
...
@@ -2202,27 +3154,28 @@ Terminal.prototype.send = function(data) {
...
@@ -2202,27 +3154,28 @@ Terminal.prototype.send = function(data) {
};
};
Terminal.prototype.bell = function() {
Terminal.prototype.bell = function() {
if (!Terminal.visualBell) return;
this.emit('bell');
if (!this.visualBell) return;
var self = this;
var self = this;
this.element.style.borderColor = 'white';
this.element.style.borderColor = 'white';
setTimeout(function() {
setTimeout(function() {
self.element.style.borderColor = '';
self.element.style.borderColor = '';
}, 10);
}, 10);
if (
Terminal
.popOnBell) this.focus();
if (
this
.popOnBell) this.focus();
};
};
Terminal.prototype.log = function() {
Terminal.prototype.log = function() {
if (!
Terminal
.debug) return;
if (!
this
.debug) return;
if (!
window.console || !window
.console.log) return;
if (!
this.context.console || !this.context
.console.log) return;
var args = Array.prototype.slice.call(arguments);
var args = Array.prototype.slice.call(arguments);
window.console.log.apply(window
.console, args);
this.context.console.log.apply(this.context
.console, args);
};
};
Terminal.prototype.error = function() {
Terminal.prototype.error = function() {
if (!
Terminal
.debug) return;
if (!
this
.debug) return;
if (!
window.console || !window
.console.error) return;
if (!
this.context.console || !this.context
.console.error) return;
var args = Array.prototype.slice.call(arguments);
var args = Array.prototype.slice.call(arguments);
window.console.error.apply(window
.console, args);
this.context.console.error.apply(this.context
.console, args);
};
};
Terminal.prototype.resize = function(x, y) {
Terminal.prototype.resize = function(x, y) {
...
@@ -2238,7 +3191,7 @@ Terminal.prototype.resize = function(x, y) {
...
@@ -2238,7 +3191,7 @@ Terminal.prototype.resize = function(x, y) {
// resize cols
// resize cols
j = this.cols;
j = this.cols;
if (j < x) {
if (j < x) {
ch = [this.defAttr, ' '];
ch = [this.defAttr, ' '];
// does xterm use the default attr?
i = this.lines.length;
i = this.lines.length;
while (i--) {
while (i--) {
while (this.lines[i].length < x) {
while (this.lines[i].length < x) {
...
@@ -2255,6 +3208,7 @@ Terminal.prototype.resize = function(x, y) {
...
@@ -2255,6 +3208,7 @@ Terminal.prototype.resize = function(x, y) {
}
}
this.setupStops(j);
this.setupStops(j);
this.cols = x;
this.cols = x;
this.columns = x;
// resize rows
// resize rows
j = this.rows;
j = this.rows;
...
@@ -2265,7 +3219,7 @@ Terminal.prototype.resize = function(x, y) {
...
@@ -2265,7 +3219,7 @@ Terminal.prototype.resize = function(x, y) {
this.lines.push(this.blankLine());
this.lines.push(this.blankLine());
}
}
if (this.children.length < y) {
if (this.children.length < y) {
line = document.createElement('div');
line =
this.
document.createElement('div');
el.appendChild(line);
el.appendChild(line);
this.children.push(line);
this.children.push(line);
}
}
...
@@ -2298,11 +3252,20 @@ Terminal.prototype.resize = function(x, y) {
...
@@ -2298,11 +3252,20 @@ Terminal.prototype.resize = function(x, y) {
// screen buffer. just set it
// screen buffer. just set it
// to null for now.
// to null for now.
this.normal = null;
this.normal = null;
// Act as though we are a node TTY stream:
this.emit('resize');
};
};
Terminal.prototype.updateRange = function(y) {
Terminal.prototype.updateRange = function(y) {
if (y < this.refreshStart) this.refreshStart = y;
if (y < this.refreshStart) this.refreshStart = y;
if (y > this.refreshEnd) this.refreshEnd = y;
if (y > this.refreshEnd) this.refreshEnd = y;
// if (y > this.refreshEnd) {
// this.refreshEnd = y;
// if (y > this.rows - 1) {
// this.refreshEnd = this.rows - 1;
// }
// }
};
};
Terminal.prototype.maxRange = function() {
Terminal.prototype.maxRange = function() {
...
@@ -2341,9 +3304,16 @@ Terminal.prototype.nextStop = function(x) {
...
@@ -2341,9 +3304,16 @@ Terminal.prototype.nextStop = function(x) {
: x < 0 ? 0 : x;
: x < 0 ? 0 : x;
};
};
// back_color_erase feature for xterm.
Terminal.prototype.eraseAttr = function() {
// if (this.is('screen')) return this.defAttr;
return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
};
Terminal.prototype.eraseRight = function(x, y) {
Terminal.prototype.eraseRight = function(x, y) {
var line = this.lines[this.ybase + y]
var line = this.lines[this.ybase + y]
, ch = [this.curAttr, ' ']; // xterm
, ch = [this.eraseAttr(), ' ']; // xterm
for (; x < this.cols; x++) {
for (; x < this.cols; x++) {
line[x] = ch;
line[x] = ch;
...
@@ -2354,7 +3324,7 @@ Terminal.prototype.eraseRight = function(x, y) {
...
@@ -2354,7 +3324,7 @@ Terminal.prototype.eraseRight = function(x, y) {
Terminal.prototype.eraseLeft = function(x, y) {
Terminal.prototype.eraseLeft = function(x, y) {
var line = this.lines[this.ybase + y]
var line = this.lines[this.ybase + y]
, ch = [this.
curAttr
, ' ']; // xterm
, ch = [this.
eraseAttr()
, ' ']; // xterm
x++;
x++;
while (x--) line[x] = ch;
while (x--) line[x] = ch;
...
@@ -2368,7 +3338,7 @@ Terminal.prototype.eraseLine = function(y) {
...
@@ -2368,7 +3338,7 @@ Terminal.prototype.eraseLine = function(y) {
Terminal.prototype.blankLine = function(cur) {
Terminal.prototype.blankLine = function(cur) {
var attr = cur
var attr = cur
? this.
curAttr
? this.
eraseAttr()
: this.defAttr;
: this.defAttr;
var ch = [attr, ' ']
var ch = [attr, ' ']
...
@@ -2384,12 +3354,12 @@ Terminal.prototype.blankLine = function(cur) {
...
@@ -2384,12 +3354,12 @@ Terminal.prototype.blankLine = function(cur) {
Terminal.prototype.ch = function(cur) {
Terminal.prototype.ch = function(cur) {
return cur
return cur
? [this.
curAttr
, ' ']
? [this.
eraseAttr()
, ' ']
: [this.defAttr, ' '];
: [this.defAttr, ' '];
};
};
Terminal.prototype.is = function(term) {
Terminal.prototype.is = function(term) {
var name = this.termName
|| Terminal.termName
;
var name = this.termName;
return (name + '').indexOf(term) === 0;
return (name + '').indexOf(term) === 0;
};
};
...
@@ -2436,8 +3406,9 @@ Terminal.prototype.reverseIndex = function() {
...
@@ -2436,8 +3406,9 @@ Terminal.prototype.reverseIndex = function() {
// ESC c Full Reset (RIS).
// ESC c Full Reset (RIS).
Terminal.prototype.reset = function() {
Terminal.prototype.reset = function() {
//Terminal.call(this, this.cols, this.rows);
this.options.rows = this.rows;
Terminal.call(this, this.cols, this.rows, this.handler);
this.options.cols = this.cols;
Terminal.call(this, this.options);
this.refresh(0, this.rows - 1);
this.refresh(0, this.rows - 1);
};
};
...
@@ -2643,84 +3614,120 @@ Terminal.prototype.eraseInLine = function(params) {
...
@@ -2643,84 +3614,120 @@ Terminal.prototype.eraseInLine = function(params) {
// Ps = 4 8 ; 5 ; Ps -> Set background color to the second
// Ps = 4 8 ; 5 ; Ps -> Set background color to the second
// Ps.
// Ps.
Terminal.prototype.charAttributes = function(params) {
Terminal.prototype.charAttributes = function(params) {
// Optimize a single SGR0.
if (params.length === 1 && params[0] === 0) {
this.curAttr = this.defAttr;
return;
}
var l = params.length
var l = params.length
, i = 0
, i = 0
, bg
, flags = this.curAttr >> 18
, fg
, fg = (this.curAttr >> 9) & 0x1ff
, bg = this.curAttr & 0x1ff
, p;
, p;
for (; i < l; i++) {
for (; i < l; i++) {
p = params[i];
p = params[i];
if (p >= 30 && p <= 37) {
if (p >= 30 && p <= 37) {
// fg color 8
// fg color 8
this.curAttr = (this.curAttr & ~(0x1ff << 9)) | ((p - 30) << 9)
;
fg = p - 30
;
} else if (p >= 40 && p <= 47) {
} else if (p >= 40 && p <= 47) {
// bg color 8
// bg color 8
this.curAttr = (this.curAttr & ~0x1ff) | (p - 40)
;
bg = p - 40
;
} else if (p >= 90 && p <= 97) {
} else if (p >= 90 && p <= 97) {
// fg color 16
// fg color 16
p += 8;
p += 8;
this.curAttr = (this.curAttr & ~(0x1ff << 9)) | ((p - 90) << 9)
;
fg = p - 90
;
} else if (p >= 100 && p <= 107) {
} else if (p >= 100 && p <= 107) {
// bg color 16
// bg color 16
p += 8;
p += 8;
this.curAttr = (this.curAttr & ~0x1ff) | (p - 100)
;
bg = p - 100
;
} else if (p === 0) {
} else if (p === 0) {
// default
// default
this.curAttr = this.defAttr;
flags = this.defAttr >> 18;
fg = (this.defAttr >> 9) & 0x1ff;
bg = this.defAttr & 0x1ff;
// flags = 0;
// fg = 0x1ff;
// bg = 0x1ff;
} else if (p === 1) {
} else if (p === 1) {
// bold text
// bold text
this.curAttr = this.curAttr | (1 << 18)
;
flags |= 1
;
} else if (p === 4) {
} else if (p === 4) {
// underlined text
// underlined text
this.curAttr = this.curAttr | (2 << 18);
flags |= 2;
} else if (p === 7 || p === 27) {
} else if (p === 5) {
// blink
flags |= 4;
} else if (p === 7) {
// inverse and positive
// inverse and positive
// test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
// test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
if (p === 7) {
flags |= 8;
if ((this.curAttr >> 18) & 4) continue;
} else if (p === 8) {
this.curAttr = this.curAttr | (4 << 18);
// invisible
} else if (p === 27) {
flags |= 16;
if (~(this.curAttr >> 18) & 4) continue;
this.curAttr = this.curAttr & ~(4 << 18);
}
bg = this.curAttr & 0x1ff;
fg = (this.curAttr >> 9) & 0x1ff;
this.curAttr = (this.curAttr & ~0x3ffff) | ((bg << 9) | fg);
} else if (p === 22) {
} else if (p === 22) {
// not bold
// not bold
this.curAttr = this.curAttr & ~(1 << 18)
;
flags &= ~1
;
} else if (p === 24) {
} else if (p === 24) {
// not underlined
// not underlined
this.curAttr = this.curAttr & ~(2 << 18);
flags &= ~2;
} else if (p === 25) {
// not blink
flags &= ~4;
} else if (p === 27) {
// not inverse
flags &= ~8;
} else if (p === 28) {
// not invisible
flags &= ~16;
} else if (p === 39) {
} else if (p === 39) {
// reset fg
// reset fg
this.curAttr = this.curAttr & ~(0x1ff << 9);
fg = (this.defAttr >> 9) & 0x1ff;
this.curAttr = this.curAttr | (((this.defAttr >> 9) & 0x1ff) << 9);
} else if (p === 49) {
} else if (p === 49) {
// reset bg
// reset bg
this.curAttr = this.curAttr & ~0x1ff;
bg = this.defAttr & 0x1ff;
this.curAttr = this.curAttr | (this.defAttr & 0x1ff);
} else if (p === 38) {
} else if (p === 38) {
// fg color 256
// fg color 256
if (params[i+1] !== 5) continue;
if (params[i + 1] === 2) {
i += 2;
fg = matchColor(
params[i] & 0xff,
params[i + 1] & 0xff,
params[i + 2] & 0xff);
if (fg === -1) fg = 0x1ff;
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
i += 2;
p = params[i] & 0xff;
p = params[i] & 0xff;
// convert 88 colors to 256
fg = p;
// if (this.is('rxvt-unicode') && p < 88) p = p * 2.9090 | 0;
}
this.curAttr = (this.curAttr & ~(0x1ff << 9)) | (p << 9);
} else if (p === 48) {
} else if (p === 48) {
// bg color 256
// bg color 256
if (params[i+1] !== 5) continue;
if (params[i + 1] === 2) {
i += 2;
bg = matchColor(
params[i] & 0xff,
params[i + 1] & 0xff,
params[i + 2] & 0xff);
if (bg === -1) bg = 0x1ff;
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
i += 2;
p = params[i] & 0xff;
p = params[i] & 0xff;
// convert 88 colors to 256
bg = p;
// if (this.is('rxvt-unicode') && p < 88) p = p * 2.9090 | 0;
}
this.curAttr = (this.curAttr & ~0x1ff) | p;
} else if (p === 100) {
// reset fg/bg
fg = (this.defAttr >> 9) & 0x1ff;
bg = this.defAttr & 0x1ff;
} else {
this.error('Unknown SGR attribute: %d.', p);
}
}
}
}
this.curAttr = (flags << 18) | (fg << 9) | bg;
};
};
// CSI Ps n Device Status Report (DSR).
// CSI Ps n Device Status Report (DSR).
...
@@ -2777,7 +3784,7 @@ Terminal.prototype.deviceStatus = function(params) {
...
@@ -2777,7 +3784,7 @@ Terminal.prototype.deviceStatus = function(params) {
// this.send('\x1b[?11n');
// this.send('\x1b[?11n');
break;
break;
case 25:
case 25:
// dont support user defined
role_
keys
// dont support user defined keys
// this.send('\x1b[?21n');
// this.send('\x1b[?21n');
break;
break;
case 26:
case 26:
...
@@ -2806,7 +3813,7 @@ Terminal.prototype.insertChars = function(params) {
...
@@ -2806,7 +3813,7 @@ Terminal.prototype.insertChars = function(params) {
row = this.y + this.ybase;
row = this.y + this.ybase;
j = this.x;
j = this.x;
ch = [this.
curAttr
, ' ']; // xterm
ch = [this.
eraseAttr()
, ' ']; // xterm
while (param-- && j < this.cols) {
while (param-- && j < this.cols) {
this.lines[row].splice(j++, 0, ch);
this.lines[row].splice(j++, 0, ch);
...
@@ -2903,7 +3910,7 @@ Terminal.prototype.deleteChars = function(params) {
...
@@ -2903,7 +3910,7 @@ Terminal.prototype.deleteChars = function(params) {
if (param < 1) param = 1;
if (param < 1) param = 1;
row = this.y + this.ybase;
row = this.y + this.ybase;
ch = [this.
curAttr
, ' ']; // xterm
ch = [this.
eraseAttr()
, ' ']; // xterm
while (param--) {
while (param--) {
this.lines[row].splice(this.x, 1);
this.lines[row].splice(this.x, 1);
...
@@ -2921,7 +3928,7 @@ Terminal.prototype.eraseChars = function(params) {
...
@@ -2921,7 +3928,7 @@ Terminal.prototype.eraseChars = function(params) {
row = this.y + this.ybase;
row = this.y + this.ybase;
j = this.x;
j = this.x;
ch = [this.
curAttr
, ' ']; // xterm
ch = [this.
eraseAttr()
, ' ']; // xterm
while (param-- && j < this.cols) {
while (param-- && j < this.cols) {
this.lines[row][j++] = ch;
this.lines[row][j++] = ch;
...
@@ -2964,7 +3971,7 @@ Terminal.prototype.HPositionRelative = function(params) {
...
@@ -2964,7 +3971,7 @@ Terminal.prototype.HPositionRelative = function(params) {
// Ps = 1 -> 132-columns.
// Ps = 1 -> 132-columns.
// Ps = 2 -> Printer.
// Ps = 2 -> Printer.
// Ps = 6 -> Selective erase.
// Ps = 6 -> Selective erase.
// Ps = 8 -> User-defined
role_
keys.
// Ps = 8 -> User-defined keys.
// Ps = 9 -> National replacement character sets.
// Ps = 9 -> National replacement character sets.
// Ps = 1 5 -> Technical characters.
// Ps = 1 5 -> Technical characters.
// Ps = 2 2 -> ANSI color, e.g., VT525.
// Ps = 2 2 -> ANSI color, e.g., VT525.
...
@@ -3105,7 +4112,7 @@ Terminal.prototype.HVPosition = function(params) {
...
@@ -3105,7 +4112,7 @@ Terminal.prototype.HVPosition = function(params) {
// Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
// Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
// (enables the eightBitInput resource).
// (enables the eightBitInput resource).
// Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
// Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
// Lock
role_
keys. (This enables the numLock resource).
// Lock keys. (This enables the numLock resource).
// Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
// Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
// enables the metaSendsEscape resource).
// enables the metaSendsEscape resource).
// Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
// Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
...
@@ -3163,7 +4170,7 @@ Terminal.prototype.setMode = function(params) {
...
@@ -3163,7 +4170,7 @@ Terminal.prototype.setMode = function(params) {
}
else
if
(
this
.
prefix
===
'?'
)
{
}
else
if
(
this
.
prefix
===
'?'
)
{
switch
(
params
)
{
switch
(
params
)
{
case
1
:
case
1
:
this
.
application
Keypad
=
true
;
this
.
application
Cursor
=
true
;
break
;
break
;
case
2
:
case
2
:
this
.
setgCharset
(
0
,
Terminal
.
charsets
.
US
);
this
.
setgCharset
(
0
,
Terminal
.
charsets
.
US
);
...
@@ -3185,6 +4192,10 @@ Terminal.prototype.setMode = function(params) {
...
@@ -3185,6 +4192,10 @@ Terminal.prototype.setMode = function(params) {
case
12
:
case
12
:
// this.cursorBlink = true;
// this.cursorBlink = true;
break
;
break
;
case
66
:
this
.
log
(
'Serial port requested application keypad.'
);
this
.
applicationKeypad
=
true
;
break
;
case
9
:
// X10 Mouse
case
9
:
// X10 Mouse
// no release, no motion, no wheel, no modifiers.
// no release, no motion, no wheel, no modifiers.
case
1000
:
// vt200 mouse
case
1000
:
// vt200 mouse
...
@@ -3304,7 +4315,7 @@ Terminal.prototype.setMode = function(params) {
...
@@ -3304,7 +4315,7 @@ Terminal.prototype.setMode = function(params) {
// Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
// Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
// the eightBitInput resource).
// the eightBitInput resource).
// Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
// Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
// Lock
role_
keys. (This disables the numLock resource).
// Lock keys. (This disables the numLock resource).
// Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
// Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
// (This disables the metaSendsEscape resource).
// (This disables the metaSendsEscape resource).
// Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
// Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
...
@@ -3361,7 +4372,7 @@ Terminal.prototype.resetMode = function(params) {
...
@@ -3361,7 +4372,7 @@ Terminal.prototype.resetMode = function(params) {
}
else
if
(
this
.
prefix
===
'?'
)
{
}
else
if
(
this
.
prefix
===
'?'
)
{
switch
(
params
)
{
switch
(
params
)
{
case
1
:
case
1
:
this
.
application
Keypad
=
false
;
this
.
application
Cursor
=
false
;
break
;
break
;
case
3
:
case
3
:
if
(
this
.
cols
===
132
&&
this
.
savedCols
)
{
if
(
this
.
cols
===
132
&&
this
.
savedCols
)
{
...
@@ -3378,6 +4389,10 @@ Terminal.prototype.resetMode = function(params) {
...
@@ -3378,6 +4389,10 @@ Terminal.prototype.resetMode = function(params) {
case
12
:
case
12
:
// this.cursorBlink = false;
// this.cursorBlink = false;
break
;
break
;
case
66
:
this
.
log
(
'Switching back to normal keypad.'
);
this
.
applicationKeypad
=
false
;
break
;
case
9
:
// X10 Mouse
case
9
:
// X10 Mouse
case
1000
:
// vt200 mouse
case
1000
:
// vt200 mouse
case
1002
:
// button event mouse
case
1002
:
// button event mouse
...
@@ -3588,7 +4603,7 @@ Terminal.prototype.setResources = function(params) {
...
@@ -3588,7 +4603,7 @@ Terminal.prototype.setResources = function(params) {
// Ps = 4 -> modifyOtherKeys.
// Ps = 4 -> modifyOtherKeys.
// If the parameter is omitted, modifyFunctionKeys is disabled.
// If the parameter is omitted, modifyFunctionKeys is disabled.
// When modifyFunctionKeys is disabled, xterm uses the modifier
// When modifyFunctionKeys is disabled, xterm uses the modifier
//
role_
keys to make an extended sequence of functions rather than
// keys to make an extended sequence of functions rather than
// adding a parameter to each function key to denote the modi-
// adding a parameter to each function key to denote the modi-
// fiers.
// fiers.
Terminal
.
prototype
.
disableModifiers
=
function
(
params
)
{
Terminal
.
prototype
.
disableModifiers
=
function
(
params
)
{
...
@@ -3615,6 +4630,7 @@ Terminal.prototype.softReset = function(params) {
...
@@ -3615,6 +4630,7 @@ Terminal.prototype.softReset = function(params) {
this
.
originMode
=
false
;
this
.
originMode
=
false
;
this
.
wraparoundMode
=
false
;
// autowrap
this
.
wraparoundMode
=
false
;
// autowrap
this
.
applicationKeypad
=
false
;
// ?
this
.
applicationKeypad
=
false
;
// ?
this
.
applicationCursor
=
false
;
this
.
scrollTop
=
0
;
this
.
scrollTop
=
0
;
this
.
scrollBottom
=
this
.
rows
-
1
;
this
.
scrollBottom
=
this
.
rows
-
1
;
this
.
curAttr
=
this
.
defAttr
;
this
.
curAttr
=
this
.
defAttr
;
...
@@ -3933,7 +4949,7 @@ Terminal.prototype.eraseRectangle = function(params) {
...
@@ -3933,7 +4949,7 @@ Terminal.prototype.eraseRectangle = function(params) {
,
i
,
i
,
ch
;
,
ch
;
ch
=
[
this
.
curAttr
,
' '
];
// xterm?
ch
=
[
this
.
eraseAttr
()
,
' '
];
// xterm?
for
(;
t
<
b
+
1
;
t
++
)
{
for
(;
t
<
b
+
1
;
t
++
)
{
line
=
this
.
lines
[
this
.
ybase
+
t
];
line
=
this
.
lines
[
this
.
ybase
+
t
];
...
@@ -4019,7 +5035,7 @@ Terminal.prototype.requestLocatorPosition = function(params) {
...
@@ -4019,7 +5035,7 @@ Terminal.prototype.requestLocatorPosition = function(params) {
Terminal
.
prototype
.
insertColumns
=
function
()
{
Terminal
.
prototype
.
insertColumns
=
function
()
{
var
param
=
params
[
0
]
var
param
=
params
[
0
]
,
l
=
this
.
ybase
+
this
.
rows
,
l
=
this
.
ybase
+
this
.
rows
,
ch
=
[
this
.
curAttr
,
' '
]
// xterm?
,
ch
=
[
this
.
eraseAttr
()
,
' '
]
// xterm?
,
i
;
,
i
;
while
(
param
--
)
{
while
(
param
--
)
{
...
@@ -4038,7 +5054,7 @@ Terminal.prototype.insertColumns = function() {
...
@@ -4038,7 +5054,7 @@ Terminal.prototype.insertColumns = function() {
Terminal
.
prototype
.
deleteColumns
=
function
()
{
Terminal
.
prototype
.
deleteColumns
=
function
()
{
var
param
=
params
[
0
]
var
param
=
params
[
0
]
,
l
=
this
.
ybase
+
this
.
rows
,
l
=
this
.
ybase
+
this
.
rows
,
ch
=
[
this
.
curAttr
,
' '
]
// xterm?
,
ch
=
[
this
.
eraseAttr
()
,
' '
]
// xterm?
,
i
;
,
i
;
while
(
param
--
)
{
while
(
param
--
)
{
...
@@ -4052,82 +5068,1037 @@ Terminal.prototype.deleteColumns = function() {
...
@@ -4052,82 +5068,1037 @@ Terminal.prototype.deleteColumns = function() {
};
};
/**
/**
*
Character Set
s
*
Prefix/Select/Visual/Search Mode
s
*/
*/
Terminal
.
charsets
=
{};
Terminal
.
prototype
.
enterPrefix
=
function
()
{
this
.
prefixMode
=
true
;
};
// DEC Special Character and Line Drawing Set.
Terminal
.
prototype
.
leavePrefix
=
function
()
{
// http://vt100.net/docs/vt102-ug/table5-13.html
this
.
prefixMode
=
false
;
// A lot of curses apps use this if they see TERM=xterm.
// testing: echo -e '\e(0a\e(B'
// The xterm output sometimes seems to conflict with the
// reference above. xterm seems in line with the reference
// when running vttest however.
// The table below now uses xterm's output from vttest.
Terminal
.
charsets
.
SCLD
=
{
// (0
'`'
:
'
\
u25c6'
,
// '◆'
'a'
:
'
\
u2592'
,
// '▒'
'b'
:
'
\
u0009'
,
// '\t'
'c'
:
'
\
u000c'
,
// '\f'
'd'
:
'
\
u000d'
,
// '\r'
'e'
:
'
\
u000a'
,
// '\n'
'f'
:
'
\
u00b0'
,
// '°'
'g'
:
'
\
u00b1'
,
// '±'
'h'
:
'
\
u2424'
,
// '\u2424' (NL)
'i'
:
'
\
u000b'
,
// '\v'
'j'
:
'
\
u2518'
,
// '┘'
'k'
:
'
\
u2510'
,
// '┐'
'l'
:
'
\
u250c'
,
// '┌'
'm'
:
'
\
u2514'
,
// '└'
'n'
:
'
\
u253c'
,
// '┼'
'o'
:
'
\
u23ba'
,
// '⎺'
'p'
:
'
\
u23bb'
,
// '⎻'
'q'
:
'
\
u2500'
,
// '─'
'r'
:
'
\
u23bc'
,
// '⎼'
's'
:
'
\
u23bd'
,
// '⎽'
't'
:
'
\
u251c'
,
// '├'
'u'
:
'
\
u2524'
,
// '┤'
'v'
:
'
\
u2534'
,
// '┴'
'w'
:
'
\
u252c'
,
// '┬'
'x'
:
'
\
u2502'
,
// '│'
'y'
:
'
\
u2264'
,
// '≤'
'z'
:
'
\
u2265'
,
// '≥'
'{'
:
'
\
u03c0'
,
// 'π'
'|'
:
'
\
u2260'
,
// '≠'
'}'
:
'
\
u00a3'
,
// '£'
'~'
:
'
\
u00b7'
// '·'
};
};
Terminal
.
charsets
.
UK
=
null
;
// (A
Terminal
.
prototype
.
enterSelect
=
function
()
{
Terminal
.
charsets
.
US
=
null
;
// (B (USASCII)
this
.
_real
=
{
Terminal
.
charsets
.
Dutch
=
null
;
// (4
x
:
this
.
x
,
Terminal
.
charsets
.
Finnish
=
null
;
// (C or (5
y
:
this
.
y
,
Terminal
.
charsets
.
French
=
null
;
// (R
ydisp
:
this
.
ydisp
,
Terminal
.
charsets
.
FrenchCanadian
=
null
;
// (Q
ybase
:
this
.
ybase
,
Terminal
.
charsets
.
German
=
null
;
// (K
cursorHidden
:
this
.
cursorHidden
,
Terminal
.
charsets
.
Italian
=
null
;
// (Y
lines
:
this
.
copyBuffer
(
this
.
lines
),
Terminal
.
charsets
.
NorwegianDanish
=
null
;
// (E or (6
write
:
this
.
write
Terminal
.
charsets
.
Spanish
=
null
;
// (Z
};
Terminal
.
charsets
.
Swedish
=
null
;
// (H or (7
this
.
write
=
function
()
{};
Terminal
.
charsets
.
Swiss
=
null
;
// (=
this
.
selectMode
=
true
;
Terminal
.
charsets
.
ISOLatin
=
null
;
// /A
this
.
visualMode
=
false
;
this
.
cursorHidden
=
false
;
this
.
refresh
(
this
.
y
,
this
.
y
);
};
/**
Terminal
.
prototype
.
leaveSelect
=
function
()
{
* Helpers
this
.
x
=
this
.
_real
.
x
;
*/
this
.
y
=
this
.
_real
.
y
;
this
.
ydisp
=
this
.
_real
.
ydisp
;
this
.
ybase
=
this
.
_real
.
ybase
;
this
.
cursorHidden
=
this
.
_real
.
cursorHidden
;
this
.
lines
=
this
.
_real
.
lines
;
this
.
write
=
this
.
_real
.
write
;
delete
this
.
_real
;
this
.
selectMode
=
false
;
this
.
visualMode
=
false
;
this
.
refresh
(
0
,
this
.
rows
-
1
);
};
function
on
(
el
,
type
,
handler
,
capture
)
{
Terminal
.
prototype
.
enterVisual
=
function
()
{
el
.
addEventListener
(
type
,
handler
,
capture
||
false
);
this
.
_real
.
preVisual
=
this
.
copyBuffer
(
this
.
lines
);
}
this
.
selectText
(
this
.
x
,
this
.
x
,
this
.
ydisp
+
this
.
y
,
this
.
ydisp
+
this
.
y
);
this
.
visualMode
=
true
;
};
function
off
(
el
,
type
,
handler
,
capture
)
{
Terminal
.
prototype
.
leaveVisual
=
function
()
{
el
.
removeEventListener
(
type
,
handler
,
capture
||
false
);
this
.
lines
=
this
.
_real
.
preVisual
;
}
delete
this
.
_real
.
preVisual
;
delete
this
.
_selected
;
this
.
visualMode
=
false
;
this
.
refresh
(
0
,
this
.
rows
-
1
);
};
function
cancel
(
ev
)
{
Terminal
.
prototype
.
enterSearch
=
function
(
down
)
{
if
(
ev
.
preventDefault
)
ev
.
preventDefault
();
this
.
entry
=
''
;
ev
.
returnValue
=
false
;
this
.
searchMode
=
true
;
this
.
searchDown
=
down
;
this
.
_real
.
preSearch
=
this
.
copyBuffer
(
this
.
lines
);
this
.
_real
.
preSearchX
=
this
.
x
;
this
.
_real
.
preSearchY
=
this
.
y
;
var
bottom
=
this
.
ydisp
+
this
.
rows
-
1
;
for
(
var
i
=
0
;
i
<
this
.
entryPrefix
.
length
;
i
++
)
{
//this.lines[bottom][i][0] = (this.defAttr & ~0x1ff) | 4;
//this.lines[bottom][i][1] = this.entryPrefix[i];
this
.
lines
[
bottom
][
i
]
=
[
(
this
.
defAttr
&
~
0x1ff
)
|
4
,
this
.
entryPrefix
[
i
]
];
}
this
.
y
=
this
.
rows
-
1
;
this
.
x
=
this
.
entryPrefix
.
length
;
this
.
refresh
(
this
.
rows
-
1
,
this
.
rows
-
1
);
};
Terminal
.
prototype
.
leaveSearch
=
function
()
{
this
.
searchMode
=
false
;
if
(
this
.
_real
.
preSearch
)
{
this
.
lines
=
this
.
_real
.
preSearch
;
this
.
x
=
this
.
_real
.
preSearchX
;
this
.
y
=
this
.
_real
.
preSearchY
;
delete
this
.
_real
.
preSearch
;
delete
this
.
_real
.
preSearchX
;
delete
this
.
_real
.
preSearchY
;
}
this
.
refresh
(
this
.
rows
-
1
,
this
.
rows
-
1
);
};
Terminal
.
prototype
.
copyBuffer
=
function
(
lines
)
{
var
lines
=
lines
||
this
.
lines
,
out
=
[];
for
(
var
y
=
0
;
y
<
lines
.
length
;
y
++
)
{
out
[
y
]
=
[];
for
(
var
x
=
0
;
x
<
lines
[
y
].
length
;
x
++
)
{
out
[
y
][
x
]
=
[
lines
[
y
][
x
][
0
],
lines
[
y
][
x
][
1
]];
}
}
return
out
;
};
Terminal
.
prototype
.
getCopyTextarea
=
function
(
text
)
{
var
textarea
=
this
.
_copyTextarea
,
document
=
this
.
document
;
if
(
!
textarea
)
{
textarea
=
document
.
createElement
(
'textarea'
);
textarea
.
style
.
position
=
'absolute'
;
textarea
.
style
.
left
=
'-32000px'
;
textarea
.
style
.
top
=
'-32000px'
;
textarea
.
style
.
width
=
'0px'
;
textarea
.
style
.
height
=
'0px'
;
textarea
.
style
.
opacity
=
'0'
;
textarea
.
style
.
backgroundColor
=
'transparent'
;
textarea
.
style
.
borderStyle
=
'none'
;
textarea
.
style
.
outlineStyle
=
'none'
;
document
.
getElementsByTagName
(
'body'
)[
0
].
appendChild
(
textarea
);
this
.
_copyTextarea
=
textarea
;
}
return
textarea
;
};
// NOTE: Only works for primary selection on X11.
// Non-X11 users should use Ctrl-C instead.
Terminal
.
prototype
.
copyText
=
function
(
text
)
{
var
self
=
this
,
textarea
=
this
.
getCopyTextarea
();
this
.
emit
(
'copy'
,
text
);
textarea
.
focus
();
textarea
.
textContent
=
text
;
textarea
.
value
=
text
;
textarea
.
setSelectionRange
(
0
,
text
.
length
);
setTimeout
(
function
()
{
self
.
element
.
focus
();
self
.
focus
();
},
1
);
};
Terminal
.
prototype
.
clearSelectedText
=
function
()
{
if
(
this
.
_selected
)
{
var
ox1
,
ox2
,
oy1
,
oy2
,
tmp
,
x
,
y
,
xl
,
attr
;
ox1
=
this
.
_selected
.
x1
;
ox2
=
this
.
_selected
.
x2
;
oy1
=
this
.
_selected
.
y1
;
oy2
=
this
.
_selected
.
y2
;
if
(
oy2
<
oy1
)
{
tmp
=
ox2
;
ox2
=
ox1
;
ox1
=
tmp
;
tmp
=
oy2
;
oy2
=
oy1
;
oy1
=
tmp
;
}
if
(
ox2
<
ox1
&&
oy1
===
oy2
)
{
tmp
=
ox2
;
ox2
=
ox1
;
ox1
=
tmp
;
}
for
(
y
=
oy1
;
y
<=
oy2
;
y
++
)
{
x
=
0
;
xl
=
this
.
cols
-
1
;
if
(
y
===
oy1
)
{
x
=
ox1
;
}
if
(
y
===
oy2
)
{
xl
=
ox2
;
}
for
(;
x
<=
xl
;
x
++
)
{
if
(
this
.
lines
[
y
][
x
].
old
!=
null
)
{
//this.lines[y][x][0] = this.lines[y][x].old;
//delete this.lines[y][x].old;
attr
=
this
.
lines
[
y
][
x
].
old
;
delete
this
.
lines
[
y
][
x
].
old
;
this
.
lines
[
y
][
x
]
=
[
attr
,
this
.
lines
[
y
][
x
][
1
]];
}
}
}
delete
this
.
_selected
;
}
};
Terminal
.
prototype
.
selectText
=
function
(
x1
,
x2
,
y1
,
y2
)
{
var
tmp
,
x
,
y
,
xl
,
attr
;
if
(
this
.
_selected
)
{
this
.
clearSelectedText
();
}
y1
=
Math
.
max
(
y1
,
0
);
y1
=
Math
.
min
(
y1
,
this
.
ydisp
+
this
.
rows
-
1
);
y2
=
Math
.
max
(
y2
,
0
);
y2
=
Math
.
min
(
y2
,
this
.
ydisp
+
this
.
rows
-
1
);
this
.
_selected
=
{
x1
:
x1
,
x2
:
x2
,
y1
:
y1
,
y2
:
y2
};
if
(
y2
<
y1
)
{
tmp
=
x2
;
x2
=
x1
;
x1
=
tmp
;
tmp
=
y2
;
y2
=
y1
;
y1
=
tmp
;
}
if
(
x2
<
x1
&&
y1
===
y2
)
{
tmp
=
x2
;
x2
=
x1
;
x1
=
tmp
;
}
for
(
y
=
y1
;
y
<=
y2
;
y
++
)
{
x
=
0
;
xl
=
this
.
cols
-
1
;
if
(
y
===
y1
)
{
x
=
x1
;
}
if
(
y
===
y2
)
{
xl
=
x2
;
}
for
(;
x
<=
xl
;
x
++
)
{
//this.lines[y][x].old = this.lines[y][x][0];
//this.lines[y][x][0] &= ~0x1ff;
//this.lines[y][x][0] |= (0x1ff << 9) | 4;
attr
=
this
.
lines
[
y
][
x
][
0
];
this
.
lines
[
y
][
x
]
=
[
(
attr
&
~
0x1ff
)
|
((
0x1ff
<<
9
)
|
4
),
this
.
lines
[
y
][
x
][
1
]
];
this
.
lines
[
y
][
x
].
old
=
attr
;
}
}
y1
=
y1
-
this
.
ydisp
;
y2
=
y2
-
this
.
ydisp
;
y1
=
Math
.
max
(
y1
,
0
);
y1
=
Math
.
min
(
y1
,
this
.
rows
-
1
);
y2
=
Math
.
max
(
y2
,
0
);
y2
=
Math
.
min
(
y2
,
this
.
rows
-
1
);
//this.refresh(y1, y2);
this
.
refresh
(
0
,
this
.
rows
-
1
);
};
Terminal
.
prototype
.
grabText
=
function
(
x1
,
x2
,
y1
,
y2
)
{
var
out
=
''
,
buf
=
''
,
ch
,
x
,
y
,
xl
,
tmp
;
if
(
y2
<
y1
)
{
tmp
=
x2
;
x2
=
x1
;
x1
=
tmp
;
tmp
=
y2
;
y2
=
y1
;
y1
=
tmp
;
}
if
(
x2
<
x1
&&
y1
===
y2
)
{
tmp
=
x2
;
x2
=
x1
;
x1
=
tmp
;
}
for
(
y
=
y1
;
y
<=
y2
;
y
++
)
{
x
=
0
;
xl
=
this
.
cols
-
1
;
if
(
y
===
y1
)
{
x
=
x1
;
}
if
(
y
===
y2
)
{
xl
=
x2
;
}
for
(;
x
<=
xl
;
x
++
)
{
ch
=
this
.
lines
[
y
][
x
][
1
];
if
(
ch
===
' '
)
{
buf
+=
ch
;
continue
;
}
if
(
buf
)
{
out
+=
buf
;
buf
=
''
;
}
out
+=
ch
;
if
(
isWide
(
ch
))
x
++
;
}
buf
=
''
;
out
+=
'
\
n'
;
}
// If we're not at the end of the
// line, don't add a newline.
for
(
x
=
x2
,
y
=
y2
;
x
<
this
.
cols
;
x
++
)
{
if
(
this
.
lines
[
y
][
x
][
1
]
!==
' '
)
{
out
=
out
.
slice
(
0
,
-
1
);
break
;
}
}
return
out
;
};
Terminal
.
prototype
.
keyPrefix
=
function
(
ev
,
key
)
{
if
(
key
===
'k'
||
key
===
'&'
)
{
this
.
destroy
();
}
else
if
(
key
===
'p'
||
key
===
']'
)
{
this
.
emit
(
'request paste'
);
}
else
if
(
key
===
'c'
)
{
this
.
emit
(
'request create'
);
}
else
if
(
key
>=
'0'
&&
key
<=
'9'
)
{
key
=
+
key
-
1
;
if
(
!~
key
)
key
=
9
;
this
.
emit
(
'request term'
,
key
);
}
else
if
(
key
===
'n'
)
{
this
.
emit
(
'request term next'
);
}
else
if
(
key
===
'P'
)
{
this
.
emit
(
'request term previous'
);
}
else
if
(
key
===
':'
)
{
this
.
emit
(
'request command mode'
);
}
else
if
(
key
===
'['
)
{
this
.
enterSelect
();
}
};
Terminal
.
prototype
.
keySelect
=
function
(
ev
,
key
)
{
this
.
showCursor
();
if
(
this
.
searchMode
||
key
===
'n'
||
key
===
'N'
)
{
return
this
.
keySearch
(
ev
,
key
);
}
if
(
key
===
'
\
x04'
)
{
// ctrl-d
var
y
=
this
.
ydisp
+
this
.
y
;
if
(
this
.
ydisp
===
this
.
ybase
)
{
// Mimic vim behavior
this
.
y
=
Math
.
min
(
this
.
y
+
(
this
.
rows
-
1
)
/
2
|
0
,
this
.
rows
-
1
);
this
.
refresh
(
0
,
this
.
rows
-
1
);
}
else
{
this
.
scrollDisp
((
this
.
rows
-
1
)
/
2
|
0
);
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
this
.
x
,
this
.
x
,
y
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'
\
x15'
)
{
// ctrl-u
var
y
=
this
.
ydisp
+
this
.
y
;
if
(
this
.
ydisp
===
0
)
{
// Mimic vim behavior
this
.
y
=
Math
.
max
(
this
.
y
-
(
this
.
rows
-
1
)
/
2
|
0
,
0
);
this
.
refresh
(
0
,
this
.
rows
-
1
);
}
else
{
this
.
scrollDisp
(
-
(
this
.
rows
-
1
)
/
2
|
0
);
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
this
.
x
,
this
.
x
,
y
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'
\
x06'
)
{
// ctrl-f
var
y
=
this
.
ydisp
+
this
.
y
;
this
.
scrollDisp
(
this
.
rows
-
1
);
if
(
this
.
visualMode
)
{
this
.
selectText
(
this
.
x
,
this
.
x
,
y
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'
\
x02'
)
{
// ctrl-b
var
y
=
this
.
ydisp
+
this
.
y
;
this
.
scrollDisp
(
-
(
this
.
rows
-
1
));
if
(
this
.
visualMode
)
{
this
.
selectText
(
this
.
x
,
this
.
x
,
y
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'k'
||
key
===
'
\
x1b[A'
)
{
var
y
=
this
.
ydisp
+
this
.
y
;
this
.
y
--
;
if
(
this
.
y
<
0
)
{
this
.
y
=
0
;
this
.
scrollDisp
(
-
1
);
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
this
.
x
,
this
.
x
,
y
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
this
.
y
,
this
.
y
+
1
);
}
return
;
}
if
(
key
===
'j'
||
key
===
'
\
x1b[B'
)
{
var
y
=
this
.
ydisp
+
this
.
y
;
this
.
y
++
;
if
(
this
.
y
>=
this
.
rows
)
{
this
.
y
=
this
.
rows
-
1
;
this
.
scrollDisp
(
1
);
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
this
.
x
,
this
.
x
,
y
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
this
.
y
-
1
,
this
.
y
);
}
return
;
}
if
(
key
===
'h'
||
key
===
'
\
x1b[D'
)
{
var
x
=
this
.
x
;
this
.
x
--
;
if
(
this
.
x
<
0
)
{
this
.
x
=
0
;
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
x
,
this
.
x
,
this
.
ydisp
+
this
.
y
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
this
.
y
,
this
.
y
);
}
return
;
}
if
(
key
===
'l'
||
key
===
'
\
x1b[C'
)
{
var
x
=
this
.
x
;
this
.
x
++
;
if
(
this
.
x
>=
this
.
cols
)
{
this
.
x
=
this
.
cols
-
1
;
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
x
,
this
.
x
,
this
.
ydisp
+
this
.
y
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
this
.
y
,
this
.
y
);
}
return
;
}
if
(
key
===
'v'
||
key
===
' '
)
{
if
(
!
this
.
visualMode
)
{
this
.
enterVisual
();
}
else
{
this
.
leaveVisual
();
}
return
;
}
if
(
key
===
'y'
)
{
if
(
this
.
visualMode
)
{
var
text
=
this
.
grabText
(
this
.
_selected
.
x1
,
this
.
_selected
.
x2
,
this
.
_selected
.
y1
,
this
.
_selected
.
y2
);
this
.
copyText
(
text
);
this
.
leaveVisual
();
// this.leaveSelect();
}
return
;
}
if
(
key
===
'q'
||
key
===
'
\
x1b'
)
{
if
(
this
.
visualMode
)
{
this
.
leaveVisual
();
}
else
{
this
.
leaveSelect
();
}
return
;
}
if
(
key
===
'w'
||
key
===
'W'
)
{
var
ox
=
this
.
x
;
var
oy
=
this
.
y
;
var
oyd
=
this
.
ydisp
;
var
x
=
this
.
x
;
var
y
=
this
.
y
;
var
yb
=
this
.
ydisp
;
var
saw_space
=
false
;
for
(;;)
{
var
line
=
this
.
lines
[
yb
+
y
];
while
(
x
<
this
.
cols
)
{
if
(
line
[
x
][
1
]
<=
' '
)
{
saw_space
=
true
;
}
else
if
(
saw_space
)
{
break
;
}
x
++
;
}
if
(
x
>=
this
.
cols
)
x
=
this
.
cols
-
1
;
if
(
x
===
this
.
cols
-
1
&&
line
[
x
][
1
]
<=
' '
)
{
x
=
0
;
if
(
++
y
>=
this
.
rows
)
{
y
--
;
if
(
++
yb
>
this
.
ybase
)
{
yb
=
this
.
ybase
;
x
=
this
.
x
;
break
;
}
}
continue
;
}
break
;
}
this
.
x
=
x
,
this
.
y
=
y
;
this
.
scrollDisp
(
-
this
.
ydisp
+
yb
);
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
oy
+
oyd
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'b'
||
key
===
'B'
)
{
var
ox
=
this
.
x
;
var
oy
=
this
.
y
;
var
oyd
=
this
.
ydisp
;
var
x
=
this
.
x
;
var
y
=
this
.
y
;
var
yb
=
this
.
ydisp
;
for
(;;)
{
var
line
=
this
.
lines
[
yb
+
y
];
var
saw_space
=
x
>
0
&&
line
[
x
][
1
]
>
' '
&&
line
[
x
-
1
][
1
]
>
' '
;
while
(
x
>=
0
)
{
if
(
line
[
x
][
1
]
<=
' '
)
{
if
(
saw_space
&&
(
x
+
1
<
this
.
cols
&&
line
[
x
+
1
][
1
]
>
' '
))
{
x
++
;
break
;
}
else
{
saw_space
=
true
;
}
}
x
--
;
}
if
(
x
<
0
)
x
=
0
;
if
(
x
===
0
&&
(
line
[
x
][
1
]
<=
' '
||
!
saw_space
))
{
x
=
this
.
cols
-
1
;
if
(
--
y
<
0
)
{
y
++
;
if
(
--
yb
<
0
)
{
yb
++
;
x
=
0
;
break
;
}
}
continue
;
}
break
;
}
this
.
x
=
x
,
this
.
y
=
y
;
this
.
scrollDisp
(
-
this
.
ydisp
+
yb
);
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
oy
+
oyd
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'e'
||
key
===
'E'
)
{
var
x
=
this
.
x
+
1
;
var
y
=
this
.
y
;
var
yb
=
this
.
ydisp
;
if
(
x
>=
this
.
cols
)
x
--
;
for
(;;)
{
var
line
=
this
.
lines
[
yb
+
y
];
while
(
x
<
this
.
cols
)
{
if
(
line
[
x
][
1
]
<=
' '
)
{
x
++
;
}
else
{
break
;
}
}
while
(
x
<
this
.
cols
)
{
if
(
line
[
x
][
1
]
<=
' '
)
{
if
(
x
-
1
>=
0
&&
line
[
x
-
1
][
1
]
>
' '
)
{
x
--
;
break
;
}
}
x
++
;
}
if
(
x
>=
this
.
cols
)
x
=
this
.
cols
-
1
;
if
(
x
===
this
.
cols
-
1
&&
line
[
x
][
1
]
<=
' '
)
{
x
=
0
;
if
(
++
y
>=
this
.
rows
)
{
y
--
;
if
(
++
yb
>
this
.
ybase
)
{
yb
=
this
.
ybase
;
break
;
}
}
continue
;
}
break
;
}
this
.
x
=
x
,
this
.
y
=
y
;
this
.
scrollDisp
(
-
this
.
ydisp
+
yb
);
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
oy
+
oyd
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'^'
||
key
===
'0'
)
{
var
ox
=
this
.
x
;
if
(
key
===
'0'
)
{
this
.
x
=
0
;
}
else
if
(
key
===
'^'
)
{
var
line
=
this
.
lines
[
this
.
ydisp
+
this
.
y
];
var
x
=
0
;
while
(
x
<
this
.
cols
)
{
if
(
line
[
x
][
1
]
>
' '
)
{
break
;
}
x
++
;
}
if
(
x
>=
this
.
cols
)
x
=
this
.
cols
-
1
;
this
.
x
=
x
;
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
this
.
ydisp
+
this
.
y
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
this
.
y
,
this
.
y
);
}
return
;
}
if
(
key
===
'$'
)
{
var
ox
=
this
.
x
;
var
line
=
this
.
lines
[
this
.
ydisp
+
this
.
y
];
var
x
=
this
.
cols
-
1
;
while
(
x
>=
0
)
{
if
(
line
[
x
][
1
]
>
' '
)
{
if
(
this
.
visualMode
&&
x
<
this
.
cols
-
1
)
x
++
;
break
;
}
x
--
;
}
if
(
x
<
0
)
x
=
0
;
this
.
x
=
x
;
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
this
.
ydisp
+
this
.
y
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
this
.
y
,
this
.
y
);
}
return
;
}
if
(
key
===
'g'
||
key
===
'G'
)
{
var
ox
=
this
.
x
;
var
oy
=
this
.
y
;
var
oyd
=
this
.
ydisp
;
if
(
key
===
'g'
)
{
this
.
x
=
0
,
this
.
y
=
0
;
this
.
scrollDisp
(
-
this
.
ydisp
);
}
else
if
(
key
===
'G'
)
{
this
.
x
=
0
,
this
.
y
=
this
.
rows
-
1
;
this
.
scrollDisp
(
this
.
ybase
);
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
oy
+
oyd
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'H'
||
key
===
'M'
||
key
===
'L'
)
{
var
ox
=
this
.
x
;
var
oy
=
this
.
y
;
if
(
key
===
'H'
)
{
this
.
x
=
0
,
this
.
y
=
0
;
}
else
if
(
key
===
'M'
)
{
this
.
x
=
0
,
this
.
y
=
this
.
rows
/
2
|
0
;
}
else
if
(
key
===
'L'
)
{
this
.
x
=
0
,
this
.
y
=
this
.
rows
-
1
;
}
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
this
.
ydisp
+
oy
,
this
.
ydisp
+
this
.
y
);
}
else
{
this
.
refresh
(
oy
,
oy
);
this
.
refresh
(
this
.
y
,
this
.
y
);
}
return
;
}
if
(
key
===
'{'
||
key
===
'}'
)
{
var
ox
=
this
.
x
;
var
oy
=
this
.
y
;
var
oyd
=
this
.
ydisp
;
var
line
;
var
saw_full
=
false
;
var
found
=
false
;
var
first_is_space
=
-
1
;
var
y
=
this
.
y
+
(
key
===
'{'
?
-
1
:
1
);
var
yb
=
this
.
ydisp
;
var
i
;
if
(
key
===
'{'
)
{
if
(
y
<
0
)
{
y
++
;
if
(
yb
>
0
)
yb
--
;
}
}
else
if
(
key
===
'}'
)
{
if
(
y
>=
this
.
rows
)
{
y
--
;
if
(
yb
<
this
.
ybase
)
yb
++
;
}
}
for
(;;)
{
line
=
this
.
lines
[
yb
+
y
];
for
(
i
=
0
;
i
<
this
.
cols
;
i
++
)
{
if
(
line
[
i
][
1
]
>
' '
)
{
if
(
first_is_space
===
-
1
)
{
first_is_space
=
0
;
}
saw_full
=
true
;
break
;
}
else
if
(
i
===
this
.
cols
-
1
)
{
if
(
first_is_space
===
-
1
)
{
first_is_space
=
1
;
}
else
if
(
first_is_space
===
0
)
{
found
=
true
;
}
else
if
(
first_is_space
===
1
)
{
if
(
saw_full
)
found
=
true
;
}
break
;
}
}
if
(
found
)
break
;
if
(
key
===
'{'
)
{
y
--
;
if
(
y
<
0
)
{
y
++
;
if
(
yb
>
0
)
yb
--
;
else
break
;
}
}
else
if
(
key
===
'}'
)
{
y
++
;
if
(
y
>=
this
.
rows
)
{
y
--
;
if
(
yb
<
this
.
ybase
)
yb
++
;
else
break
;
}
}
}
if
(
!
found
)
{
if
(
key
===
'{'
)
{
y
=
0
;
yb
=
0
;
}
else
if
(
key
===
'}'
)
{
y
=
this
.
rows
-
1
;
yb
=
this
.
ybase
;
}
}
this
.
x
=
0
,
this
.
y
=
y
;
this
.
scrollDisp
(
-
this
.
ydisp
+
yb
);
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
oy
+
oyd
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
if
(
key
===
'/'
||
key
===
'?'
)
{
if
(
!
this
.
visualMode
)
{
this
.
enterSearch
(
key
===
'/'
);
}
return
;
}
return
false
;
};
Terminal
.
prototype
.
keySearch
=
function
(
ev
,
key
)
{
if
(
key
===
'
\
x1b'
)
{
this
.
leaveSearch
();
return
;
}
if
(
key
===
'
\
r'
||
(
!
this
.
searchMode
&&
(
key
===
'n'
||
key
===
'N'
)))
{
this
.
leaveSearch
();
var
entry
=
this
.
entry
;
if
(
!
entry
)
{
this
.
refresh
(
0
,
this
.
rows
-
1
);
return
;
}
var
ox
=
this
.
x
;
var
oy
=
this
.
y
;
var
oyd
=
this
.
ydisp
;
var
line
;
var
found
=
false
;
var
wrapped
=
false
;
var
x
=
this
.
x
+
1
;
var
y
=
this
.
ydisp
+
this
.
y
;
var
yb
,
i
;
var
up
=
key
===
'N'
?
this
.
searchDown
:
!
this
.
searchDown
;
for
(;;)
{
line
=
this
.
lines
[
y
];
while
(
x
<
this
.
cols
)
{
for
(
i
=
0
;
i
<
entry
.
length
;
i
++
)
{
if
(
x
+
i
>=
this
.
cols
)
break
;
if
(
line
[
x
+
i
][
1
]
!==
entry
[
i
])
{
break
;
}
else
if
(
line
[
x
+
i
][
1
]
===
entry
[
i
]
&&
i
===
entry
.
length
-
1
)
{
found
=
true
;
break
;
}
}
if
(
found
)
break
;
x
+=
i
+
1
;
}
if
(
found
)
break
;
x
=
0
;
if
(
!
up
)
{
y
++
;
if
(
y
>
this
.
ybase
+
this
.
rows
-
1
)
{
if
(
wrapped
)
break
;
// this.setMessage('Search wrapped. Continuing at TOP.');
wrapped
=
true
;
y
=
0
;
}
}
else
{
y
--
;
if
(
y
<
0
)
{
if
(
wrapped
)
break
;
// this.setMessage('Search wrapped. Continuing at BOTTOM.');
wrapped
=
true
;
y
=
this
.
ybase
+
this
.
rows
-
1
;
}
}
}
if
(
found
)
{
if
(
y
-
this
.
ybase
<
0
)
{
yb
=
y
;
y
=
0
;
if
(
yb
>
this
.
ybase
)
{
y
=
yb
-
this
.
ybase
;
yb
=
this
.
ybase
;
}
}
else
{
yb
=
this
.
ybase
;
y
-=
this
.
ybase
;
}
this
.
x
=
x
,
this
.
y
=
y
;
this
.
scrollDisp
(
-
this
.
ydisp
+
yb
);
if
(
this
.
visualMode
)
{
this
.
selectText
(
ox
,
this
.
x
,
oy
+
oyd
,
this
.
ydisp
+
this
.
y
);
}
return
;
}
// this.setMessage("No matches found.");
this
.
refresh
(
0
,
this
.
rows
-
1
);
return
;
}
if
(
key
===
'
\
b'
||
key
===
'
\
x7f'
)
{
if
(
this
.
entry
.
length
===
0
)
return
;
var
bottom
=
this
.
ydisp
+
this
.
rows
-
1
;
this
.
entry
=
this
.
entry
.
slice
(
0
,
-
1
);
var
i
=
this
.
entryPrefix
.
length
+
this
.
entry
.
length
;
//this.lines[bottom][i][1] = ' ';
this
.
lines
[
bottom
][
i
]
=
[
this
.
lines
[
bottom
][
i
][
0
],
' '
];
this
.
x
--
;
this
.
refresh
(
this
.
rows
-
1
,
this
.
rows
-
1
);
this
.
refresh
(
this
.
y
,
this
.
y
);
return
;
}
if
(
key
.
length
===
1
&&
key
>=
' '
&&
key
<=
'~'
)
{
var
bottom
=
this
.
ydisp
+
this
.
rows
-
1
;
this
.
entry
+=
key
;
var
i
=
this
.
entryPrefix
.
length
+
this
.
entry
.
length
-
1
;
//this.lines[bottom][i][0] = (this.defAttr & ~0x1ff) | 4;
//this.lines[bottom][i][1] = key;
this
.
lines
[
bottom
][
i
]
=
[
(
this
.
defAttr
&
~
0x1ff
)
|
4
,
key
];
this
.
x
++
;
this
.
refresh
(
this
.
rows
-
1
,
this
.
rows
-
1
);
this
.
refresh
(
this
.
y
,
this
.
y
);
return
;
}
return
false
;
};
/**
* Character Sets
*/
Terminal
.
charsets
=
{};
// DEC Special Character and Line Drawing Set.
// http://vt100.net/docs/vt102-ug/table5-13.html
// A lot of curses apps use this if they see TERM=xterm.
// testing: echo -e '\e(0a\e(B'
// The xterm output sometimes seems to conflict with the
// reference above. xterm seems in line with the reference
// when running vttest however.
// The table below now uses xterm's output from vttest.
Terminal
.
charsets
.
SCLD
=
{
// (0
'`'
:
'
\
u25c6'
,
// '◆'
'a'
:
'
\
u2592'
,
// '▒'
'b'
:
'
\
u0009'
,
// '\t'
'c'
:
'
\
u000c'
,
// '\f'
'd'
:
'
\
u000d'
,
// '\r'
'e'
:
'
\
u000a'
,
// '\n'
'f'
:
'
\
u00b0'
,
// '°'
'g'
:
'
\
u00b1'
,
// '±'
'h'
:
'
\
u2424'
,
// '\u2424' (NL)
'i'
:
'
\
u000b'
,
// '\v'
'j'
:
'
\
u2518'
,
// '┘'
'k'
:
'
\
u2510'
,
// '┐'
'l'
:
'
\
u250c'
,
// '┌'
'm'
:
'
\
u2514'
,
// '└'
'n'
:
'
\
u253c'
,
// '┼'
'o'
:
'
\
u23ba'
,
// '⎺'
'p'
:
'
\
u23bb'
,
// '⎻'
'q'
:
'
\
u2500'
,
// '─'
'r'
:
'
\
u23bc'
,
// '⎼'
's'
:
'
\
u23bd'
,
// '⎽'
't'
:
'
\
u251c'
,
// '├'
'u'
:
'
\
u2524'
,
// '┤'
'v'
:
'
\
u2534'
,
// '┴'
'w'
:
'
\
u252c'
,
// '┬'
'x'
:
'
\
u2502'
,
// '│'
'y'
:
'
\
u2264'
,
// '≤'
'z'
:
'
\
u2265'
,
// '≥'
'{'
:
'
\
u03c0'
,
// 'π'
'|'
:
'
\
u2260'
,
// '≠'
'}'
:
'
\
u00a3'
,
// '£'
'~'
:
'
\
u00b7'
// '·'
};
Terminal
.
charsets
.
UK
=
null
;
// (A
Terminal
.
charsets
.
US
=
null
;
// (B (USASCII)
Terminal
.
charsets
.
Dutch
=
null
;
// (4
Terminal
.
charsets
.
Finnish
=
null
;
// (C or (5
Terminal
.
charsets
.
French
=
null
;
// (R
Terminal
.
charsets
.
FrenchCanadian
=
null
;
// (Q
Terminal
.
charsets
.
German
=
null
;
// (K
Terminal
.
charsets
.
Italian
=
null
;
// (Y
Terminal
.
charsets
.
NorwegianDanish
=
null
;
// (E or (6
Terminal
.
charsets
.
Spanish
=
null
;
// (Z
Terminal
.
charsets
.
Swedish
=
null
;
// (H or (7
Terminal
.
charsets
.
Swiss
=
null
;
// (=
Terminal
.
charsets
.
ISOLatin
=
null
;
// /A
/**
* Helpers
*/
function
on
(
el
,
type
,
handler
,
capture
)
{
el
.
addEventListener
(
type
,
handler
,
capture
||
false
);
}
function
off
(
el
,
type
,
handler
,
capture
)
{
el
.
removeEventListener
(
type
,
handler
,
capture
||
false
);
}
function
cancel
(
ev
)
{
if
(
ev
.
preventDefault
)
ev
.
preventDefault
();
ev
.
returnValue
=
false
;
if
(
ev
.
stopPropagation
)
ev
.
stopPropagation
();
if
(
ev
.
stopPropagation
)
ev
.
stopPropagation
();
ev
.
cancelBubble
=
true
;
ev
.
cancelBubble
=
true
;
return
false
;
return
false
;
...
@@ -4141,18 +6112,22 @@ function inherits(child, parent) {
...
@@ -4141,18 +6112,22 @@ function inherits(child, parent) {
child
.
prototype
=
new
f
;
child
.
prototype
=
new
f
;
}
}
var
isMac
=
~
navigator
.
userAgent
.
indexOf
(
'Mac'
);
// if bold is broken, we can't
// if bold is broken, we can't
// use it in the terminal.
// use it in the terminal.
function
isBoldBroken
()
{
function
isBoldBroken
(
document
)
{
var
body
=
document
.
getElementsByTagName
(
'body'
)[
0
];
var
terminal
=
document
.
createElement
(
'div'
);
terminal
.
className
=
'terminal'
;
var
line
=
document
.
createElement
(
'div'
);
var
el
=
document
.
createElement
(
'span'
);
var
el
=
document
.
createElement
(
'span'
);
el
.
innerHTML
=
'hello world'
;
el
.
innerHTML
=
'hello world'
;
document
.
body
.
appendChild
(
el
);
line
.
appendChild
(
el
);
terminal
.
appendChild
(
line
);
body
.
appendChild
(
terminal
);
var
w1
=
el
.
scrollWidth
;
var
w1
=
el
.
scrollWidth
;
el
.
style
.
fontWeight
=
'bold'
;
el
.
style
.
fontWeight
=
'bold'
;
var
w2
=
el
.
scrollWidth
;
var
w2
=
el
.
scrollWidth
;
document
.
body
.
removeChild
(
e
l
);
body
.
removeChild
(
termina
l
);
return
w1
!==
w2
;
return
w1
!==
w2
;
}
}
...
@@ -4160,12 +6135,128 @@ var String = this.String;
...
@@ -4160,12 +6135,128 @@ var String = this.String;
var
setTimeout
=
this
.
setTimeout
;
var
setTimeout
=
this
.
setTimeout
;
var
setInterval
=
this
.
setInterval
;
var
setInterval
=
this
.
setInterval
;
function
indexOf
(
obj
,
el
)
{
var
i
=
obj
.
length
;
while
(
i
--
)
{
if
(
obj
[
i
]
===
el
)
return
i
;
}
return
-
1
;
}
/* Ref: https://github.com/ajaxorg/ace/blob/0c66e1eda418477a9efbd0d3ef61698478cc607f/lib/ace/edit_session.js#L2434 */
function
isFullWidth
(
c
)
{
if
(
c
<
0x1100
)
return
false
;
return
c
>=
0x1100
&&
c
<=
0x115F
||
c
>=
0x11A3
&&
c
<=
0x11A7
||
c
>=
0x11FA
&&
c
<=
0x11FF
||
c
>=
0x2329
&&
c
<=
0x232A
||
c
>=
0x2E80
&&
c
<=
0x2E99
||
c
>=
0x2E9B
&&
c
<=
0x2EF3
||
c
>=
0x2F00
&&
c
<=
0x2FD5
||
c
>=
0x2FF0
&&
c
<=
0x2FFB
||
c
>=
0x3000
&&
c
<=
0x303E
||
c
>=
0x3041
&&
c
<=
0x3096
||
c
>=
0x3099
&&
c
<=
0x30FF
||
c
>=
0x3105
&&
c
<=
0x312D
||
c
>=
0x3131
&&
c
<=
0x318E
||
c
>=
0x3190
&&
c
<=
0x31BA
||
c
>=
0x31C0
&&
c
<=
0x31E3
||
c
>=
0x31F0
&&
c
<=
0x321E
||
c
>=
0x3220
&&
c
<=
0x3247
||
c
>=
0x3250
&&
c
<=
0x32FE
||
c
>=
0x3300
&&
c
<=
0x4DBF
||
c
>=
0x4E00
&&
c
<=
0xA48C
||
c
>=
0xA490
&&
c
<=
0xA4C6
||
c
>=
0xA960
&&
c
<=
0xA97C
||
c
>=
0xAC00
&&
c
<=
0xD7A3
||
c
>=
0xD7B0
&&
c
<=
0xD7C6
||
c
>=
0xD7CB
&&
c
<=
0xD7FB
||
c
>=
0xF900
&&
c
<=
0xFAFF
||
c
>=
0xFE10
&&
c
<=
0xFE19
||
c
>=
0xFE30
&&
c
<=
0xFE52
||
c
>=
0xFE54
&&
c
<=
0xFE66
||
c
>=
0xFE68
&&
c
<=
0xFE6B
||
c
>=
0xFF01
&&
c
<=
0xFF60
||
c
>=
0xFFE0
&&
c
<=
0xFFE6
;
};
function
isWide
(
ch
)
{
var
c
=
ch
.
charCodeAt
(
0
);
return
isFullWidth
(
c
);
}
function
matchColor
(
r1
,
g1
,
b1
)
{
var
hash
=
(
r1
<<
16
)
|
(
g1
<<
8
)
|
b1
;
if
(
matchColor
.
_cache
[
hash
]
!=
null
)
{
return
matchColor
.
_cache
[
hash
];
}
var
ldiff
=
Infinity
,
li
=
-
1
,
i
=
0
,
c
,
r2
,
g2
,
b2
,
diff
;
for
(;
i
<
Terminal
.
vcolors
.
length
;
i
++
)
{
c
=
Terminal
.
vcolors
[
i
];
r2
=
c
[
0
];
g2
=
c
[
1
];
b2
=
c
[
2
];
diff
=
matchColor
.
distance
(
r1
,
g1
,
b1
,
r2
,
g2
,
b2
);
if
(
diff
===
0
)
{
li
=
i
;
break
;
}
if
(
diff
<
ldiff
)
{
ldiff
=
diff
;
li
=
i
;
}
}
return
matchColor
.
_cache
[
hash
]
=
li
;
}
matchColor
.
_cache
=
{};
// http://stackoverflow.com/questions/1633828
matchColor
.
distance
=
function
(
r1
,
g1
,
b1
,
r2
,
g2
,
b2
)
{
return
Math
.
pow
(
30
*
(
r1
-
r2
),
2
)
+
Math
.
pow
(
59
*
(
g1
-
g2
),
2
)
+
Math
.
pow
(
11
*
(
b1
-
b2
),
2
);
};
function
each
(
obj
,
iter
,
con
)
{
if
(
obj
.
forEach
)
return
obj
.
forEach
(
iter
,
con
);
for
(
var
i
=
0
;
i
<
obj
.
length
;
i
++
)
{
iter
.
call
(
con
,
obj
[
i
],
i
,
obj
);
}
}
function
keys
(
obj
)
{
if
(
Object
.
keys
)
return
Object
.
keys
(
obj
);
var
key
,
keys
=
[];
for
(
key
in
obj
)
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
obj
,
key
))
{
keys
.
push
(
key
);
}
}
return
keys
;
}
/**
/**
* Expose
* Expose
*/
*/
Terminal
.
EventEmitter
=
EventEmitter
;
Terminal
.
EventEmitter
=
EventEmitter
;
Terminal
.
isMac
=
isMac
;
Terminal
.
Stream
=
Stream
;
Terminal
.
inherits
=
inherits
;
Terminal
.
inherits
=
inherits
;
Terminal
.
on
=
on
;
Terminal
.
on
=
on
;
Terminal
.
off
=
off
;
Terminal
.
off
=
off
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment