如果你看到了这个页面,证明你访问的不是nginx监听的端口,祝你好运"
"div>"
-#: ops/api.py:81
+#: ops/api/celery.py:32
msgid "Waiting ..."
msgstr ""
@@ -2232,116 +2274,132 @@ msgstr ""
msgid "Callback"
msgstr "回调"
-#: ops/models/adhoc.py:156 ops/templates/ops/adhoc_detail.html:114
+#: ops/models/adhoc.py:158 ops/templates/ops/adhoc_detail.html:114
msgid "Tasks"
msgstr "任务"
-#: ops/models/adhoc.py:157 ops/templates/ops/adhoc_detail.html:57
+#: ops/models/adhoc.py:159 ops/templates/ops/adhoc_detail.html:57
#: ops/templates/ops/task_adhoc.html:60
msgid "Pattern"
msgstr "模式"
-#: ops/models/adhoc.py:158 ops/templates/ops/adhoc_detail.html:61
+#: ops/models/adhoc.py:160 ops/templates/ops/adhoc_detail.html:61
msgid "Options"
msgstr "选项"
-#: ops/models/adhoc.py:160
+#: ops/models/adhoc.py:163
msgid "Run as admin"
msgstr "再次执行"
-#: ops/models/adhoc.py:161 ops/templates/ops/adhoc_detail.html:72
-#: ops/templates/ops/adhoc_detail.html:77 ops/templates/ops/task_adhoc.html:61
-msgid "Run as"
-msgstr "用户"
-
-#: ops/models/adhoc.py:162 ops/templates/ops/adhoc_detail.html:82
+#: ops/models/adhoc.py:165 ops/templates/ops/adhoc_detail.html:82
#: ops/templates/ops/task_adhoc.html:62
msgid "Become"
msgstr "Become"
-#: ops/models/adhoc.py:163 users/templates/users/user_group_detail.html:59
+#: ops/models/adhoc.py:166 users/templates/users/user_group_detail.html:59
#: xpack/plugins/cloud/templates/cloud/account_detail.html:64
#: xpack/plugins/orgs/templates/orgs/org_detail.html:56
msgid "Create by"
msgstr "创建者"
-#: ops/models/adhoc.py:327
+#: ops/models/adhoc.py:321
msgid "Start time"
msgstr "开始时间"
-#: ops/models/adhoc.py:328
+#: ops/models/adhoc.py:322
msgid "End time"
msgstr "完成时间"
-#: ops/models/adhoc.py:329 ops/templates/ops/adhoc_history.html:57
+#: ops/models/adhoc.py:323 ops/templates/ops/adhoc_history.html:57
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:41
msgid "Time"
msgstr "时间"
-#: ops/models/adhoc.py:330 ops/templates/ops/adhoc_detail.html:106
+#: ops/models/adhoc.py:324 ops/templates/ops/adhoc_detail.html:106
#: ops/templates/ops/adhoc_history.html:55
#: ops/templates/ops/adhoc_history_detail.html:69
-#: ops/templates/ops/task_detail.html:83 ops/templates/ops/task_history.html:61
+#: ops/templates/ops/task_detail.html:84 ops/templates/ops/task_history.html:61
msgid "Is finished"
msgstr "是否完成"
-#: ops/models/adhoc.py:331 ops/templates/ops/adhoc_history.html:56
+#: ops/models/adhoc.py:325 ops/templates/ops/adhoc_history.html:56
#: ops/templates/ops/task_history.html:62
msgid "Is success"
msgstr "是否成功"
-#: ops/models/adhoc.py:332
+#: ops/models/adhoc.py:326
msgid "Adhoc raw result"
msgstr "结果"
-#: ops/models/adhoc.py:333
+#: ops/models/adhoc.py:327
msgid "Adhoc result summary"
msgstr "汇总"
+#: ops/models/command.py:20 xpack/plugins/cloud/models.py:169
+msgid "Result"
+msgstr "结果"
+
+#: ops/models/command.py:52
+msgid "Task start"
+msgstr "任务开始: "
+
+#: ops/models/command.py:64
+msgid "Command `{}` is forbidden ........"
+msgstr "命令 `{}` 不允许被执行 ......."
+
+#: ops/models/command.py:70
+msgid "Task end"
+msgstr "任务结束"
+
#: ops/templates/ops/adhoc_detail.html:19
#: ops/templates/ops/adhoc_history.html:19
msgid "Version detail"
msgstr "版本详情"
#: ops/templates/ops/adhoc_detail.html:22
-#: ops/templates/ops/adhoc_history.html:22 ops/views.py:105
+#: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:124
msgid "Version run history"
msgstr "执行历史"
+#: ops/templates/ops/adhoc_detail.html:72
+#: ops/templates/ops/adhoc_detail.html:77 ops/templates/ops/task_adhoc.html:61
+msgid "Run as"
+msgstr "用户"
+
#: ops/templates/ops/adhoc_detail.html:94 ops/templates/ops/task_list.html:36
msgid "Run times"
msgstr "执行次数"
-#: ops/templates/ops/adhoc_detail.html:98 ops/templates/ops/task_detail.html:75
+#: ops/templates/ops/adhoc_detail.html:98 ops/templates/ops/task_detail.html:76
msgid "Last run"
msgstr "最后运行"
#: ops/templates/ops/adhoc_detail.html:102
#: ops/templates/ops/adhoc_history_detail.html:65
-#: ops/templates/ops/task_detail.html:79
+#: ops/templates/ops/task_detail.html:80
msgid "Time delta"
msgstr "运行时间"
#: ops/templates/ops/adhoc_detail.html:110
#: ops/templates/ops/adhoc_history_detail.html:73
-#: ops/templates/ops/task_detail.html:87
+#: ops/templates/ops/task_detail.html:88
msgid "Is success "
msgstr "成功"
#: ops/templates/ops/adhoc_detail.html:131
-#: ops/templates/ops/task_detail.html:108
+#: ops/templates/ops/task_detail.html:109
msgid "Last run failed hosts"
msgstr "最后运行失败主机"
#: ops/templates/ops/adhoc_detail.html:151
#: ops/templates/ops/adhoc_detail.html:176
-#: ops/templates/ops/task_detail.html:128
-#: ops/templates/ops/task_detail.html:153
+#: ops/templates/ops/task_detail.html:129
+#: ops/templates/ops/task_detail.html:154
msgid "No hosts"
msgstr "没有主机"
#: ops/templates/ops/adhoc_detail.html:161
-#: ops/templates/ops/task_detail.html:138
+#: ops/templates/ops/task_detail.html:139
msgid "Last run success hosts"
msgstr "最后运行成功主机"
@@ -2361,11 +2419,12 @@ msgstr "失败/成功/总"
msgid "Version"
msgstr "版本"
-#: ops/templates/ops/adhoc_history_detail.html:19 ops/views.py:118
+#: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:137
msgid "Run history detail"
msgstr "执行历史详情"
#: ops/templates/ops/adhoc_history_detail.html:22
+#: ops/templates/ops/command_execution_list.html:47
#: terminal/backends/command/models.py:16
msgid "Output"
msgstr "输出"
@@ -2391,22 +2450,40 @@ msgstr "没有资产"
msgid "Success assets"
msgstr "成功资产"
-#: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:19
-#: ops/templates/ops/task_history.html:19 ops/views.py:53
+#: ops/templates/ops/command_execution_create.html:67
+#: terminal/templates/terminal/session_detail.html:91
+#: terminal/templates/terminal/session_detail.html:100
+msgid "Go"
+msgstr ""
+
+#: ops/templates/ops/command_execution_create.html:244
+msgid "Pending"
+msgstr ""
+
+#: ops/templates/ops/command_execution_list.html:48
+msgid "Finished"
+msgstr "结束"
+
+#: ops/templates/ops/command_execution_list.html:51
+msgid "Date finished"
+msgstr "结束日期"
+
+#: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20
+#: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:72
msgid "Task detail"
msgstr "任务详情"
-#: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:22
-#: ops/templates/ops/task_history.html:22 ops/views.py:66
+#: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23
+#: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:85
msgid "Task versions"
msgstr "任务各版本"
-#: ops/templates/ops/task_adhoc.html:25 ops/templates/ops/task_detail.html:25
+#: ops/templates/ops/task_adhoc.html:25 ops/templates/ops/task_detail.html:26
#: ops/templates/ops/task_history.html:25
msgid "Run history"
msgstr "执行历史"
-#: ops/templates/ops/task_adhoc.html:28 ops/templates/ops/task_detail.html:28
+#: ops/templates/ops/task_adhoc.html:28 ops/templates/ops/task_detail.html:29
#: ops/templates/ops/task_history.html:28
msgid "Last run output"
msgstr "输出"
@@ -2415,15 +2492,15 @@ msgstr "输出"
msgid "Versions of "
msgstr "版本"
-#: ops/templates/ops/task_detail.html:67
+#: ops/templates/ops/task_detail.html:68
msgid "Total versions"
msgstr "版本数量"
-#: ops/templates/ops/task_detail.html:71
+#: ops/templates/ops/task_detail.html:72
msgid "Latest version"
msgstr "最新版本"
-#: ops/templates/ops/task_detail.html:91
+#: ops/templates/ops/task_detail.html:92
msgid "Contents"
msgstr "内容"
@@ -2440,19 +2517,28 @@ msgstr "执行"
msgid "Task start: "
msgstr "任务开始: "
-#: ops/views.py:36 ops/views.py:52 ops/views.py:65 ops/views.py:78
-#: ops/views.py:91 ops/views.py:104 ops/views.py:117
+#: ops/utils.py:51
+msgid "Update task content: {}"
+msgstr "更新任务内容: {}"
+
+#: ops/views/adhoc.py:49 ops/views/adhoc.py:71 ops/views/adhoc.py:84
+#: ops/views/adhoc.py:97 ops/views/adhoc.py:110 ops/views/adhoc.py:123
+#: ops/views/adhoc.py:136 ops/views/command.py:43 ops/views/command.py:67
msgid "Ops"
msgstr "作业中心"
-#: ops/views.py:37 templates/_nav.html:67
+#: ops/views/adhoc.py:50 templates/_nav.html:66
msgid "Task list"
msgstr "任务列表"
-#: ops/views.py:79
+#: ops/views/adhoc.py:98
msgid "Task run history"
msgstr "执行历史"
+#: ops/views/command.py:68 templates/_nav.html:78 templates/_nav_user.html:9
+msgid "Command execution"
+msgstr "命令执行"
+
#: orgs/mixins.py:77 orgs/models.py:24
msgid "Organization"
msgstr "组织管理"
@@ -2602,7 +2688,7 @@ msgstr "文档"
msgid "Commercial support"
msgstr "商业支持"
-#: templates/_header_bar.html:89 templates/_nav_user.html:9 users/forms.py:147
+#: templates/_header_bar.html:89 templates/_nav_user.html:14 users/forms.py:147
#: users/templates/users/_user.html:39
#: users/templates/users/first_login.html:39
#: users/templates/users/user_password_update.html:40
@@ -2694,6 +2780,14 @@ msgstr ""
"\"%(user_pubkey_update)s\"> 链接 更新\n"
" "
+#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
+#: users/views/group.py:60 users/views/group.py:76 users/views/group.py:92
+#: users/views/login.py:346 users/views/user.py:68 users/views/user.py:83
+#: users/views/user.py:111 users/views/user.py:192 users/views/user.py:353
+#: users/views/user.py:403 users/views/user.py:437
+msgid "Users"
+msgstr "用户管理"
+
#: templates/_nav.html:13 users/views/user.py:69
msgid "User list"
msgstr "用户列表"
@@ -2718,11 +2812,11 @@ msgstr "历史会话"
msgid "Commands"
msgstr "命令记录"
-#: templates/_nav.html:48 templates/_nav_user.html:14
+#: templates/_nav.html:48 templates/_nav_user.html:19
msgid "Web terminal"
msgstr "Web终端"
-#: templates/_nav.html:53 templates/_nav_user.html:19
+#: templates/_nav.html:53 templates/_nav_user.html:24
msgid "File manager"
msgstr "文件管理"
@@ -2733,19 +2827,19 @@ msgstr "文件管理"
msgid "Terminal"
msgstr "终端管理"
-#: templates/_nav.html:64
+#: templates/_nav.html:63
msgid "Job Center"
msgstr "作业中心"
-#: templates/_nav.html:94
+#: templates/_nav.html:84
msgid "XPack"
msgstr ""
-#: templates/_nav.html:102 xpack/plugins/cloud/views.py:26
+#: templates/_nav.html:92 xpack/plugins/cloud/views.py:26
msgid "Account list"
msgstr "账户列表"
-#: templates/_nav.html:103
+#: templates/_nav.html:93
msgid "Sync instance"
msgstr "同步实例"
@@ -3021,11 +3115,6 @@ msgstr "该会话没有命令记录"
msgid "Replay session"
msgstr "回放会话"
-#: terminal/templates/terminal/session_detail.html:91
-#: terminal/templates/terminal/session_detail.html:100
-msgid "Go"
-msgstr ""
-
#: terminal/templates/terminal/session_detail.html:97
msgid "Monitor session"
msgstr "监控"
@@ -3153,7 +3242,7 @@ msgstr "请先进行用户名和密码验证"
msgid "MFA certification failed"
msgstr "MFA认证失败"
-#: users/api/user.py:140
+#: users/api/user.py:137
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
@@ -3342,8 +3431,8 @@ msgstr "用户名不存在"
msgid "Password expired"
msgstr "密码过期"
-#: users/models/authentication.py:74 xpack/plugins/cloud/models.py:184
-#: xpack/plugins/cloud/models.py:198
+#: users/models/authentication.py:74 xpack/plugins/cloud/models.py:163
+#: xpack/plugins/cloud/models.py:177
msgid "Failed"
msgstr "失败"
@@ -3427,7 +3516,7 @@ msgstr "安全令牌验证"
#: users/templates/users/_base_otp.html:44 users/templates/users/_user.html:13
#: users/templates/users/user_profile_update.html:51
-#: xpack/plugins/cloud/models.py:51 xpack/plugins/cloud/models.py:133
+#: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:119
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:59
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:13
msgid "Account"
@@ -4255,7 +4344,7 @@ msgstr "MFA 解绑成功"
msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面"
-#: xpack/plugins/cloud/api.py:60 xpack/plugins/cloud/providers/base.py:83
+#: xpack/plugins/cloud/api.py:60 xpack/plugins/cloud/providers/base.py:84
msgid "Account unavailable"
msgstr "账户无效"
@@ -4295,145 +4384,99 @@ msgstr "选择管理员"
msgid "Cloud center"
msgstr "云管中心"
-#: xpack/plugins/cloud/models.py:30
-msgid "Aliyun"
-msgstr "阿里云"
-
-#: xpack/plugins/cloud/models.py:31
-msgid "AWS (China)"
-msgstr "AWS (中国)"
-
-#: xpack/plugins/cloud/models.py:32
-msgid "AWS (International)"
-msgstr "AWS (国际)"
-
-#: xpack/plugins/cloud/models.py:35
+#: xpack/plugins/cloud/models.py:43
msgid "Available"
msgstr "有效"
-#: xpack/plugins/cloud/models.py:36
+#: xpack/plugins/cloud/models.py:44
msgid "Unavailable"
msgstr "无效"
-#: xpack/plugins/cloud/models.py:41
+#: xpack/plugins/cloud/models.py:49
#: xpack/plugins/cloud/templates/cloud/account_detail.html:56
#: xpack/plugins/cloud/templates/cloud/account_list.html:13
msgid "Provider"
msgstr "云服务商"
-#: xpack/plugins/cloud/models.py:42
+#: xpack/plugins/cloud/models.py:50
msgid "Access key id"
msgstr ""
-#: xpack/plugins/cloud/models.py:43
+#: xpack/plugins/cloud/models.py:51
msgid "Access key secret"
msgstr ""
-#: xpack/plugins/cloud/models.py:44
+#: xpack/plugins/cloud/models.py:52
#: xpack/plugins/cloud/templates/cloud/account_detail.html:60
#: xpack/plugins/cloud/templates/cloud/account_list.html:14
msgid "Validity"
msgstr "账户状态"
-#: xpack/plugins/cloud/models.py:134
+#: xpack/plugins/cloud/models.py:120
msgid "Regions"
msgstr "地域"
-#: xpack/plugins/cloud/models.py:135
+#: xpack/plugins/cloud/models.py:121
msgid "Instances"
msgstr "实例"
-#: xpack/plugins/cloud/models.py:139
+#: xpack/plugins/cloud/models.py:125
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:75
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:17
msgid "Date last sync"
msgstr "最后同步日期"
-#: xpack/plugins/cloud/models.py:145 xpack/plugins/cloud/models.py:189
+#: xpack/plugins/cloud/models.py:131 xpack/plugins/cloud/models.py:168
msgid "Sync instance task"
msgstr "同步实例任务"
-#: xpack/plugins/cloud/models.py:185 xpack/plugins/cloud/models.py:199
+#: xpack/plugins/cloud/models.py:164 xpack/plugins/cloud/models.py:178
msgid "Succeed"
msgstr "成功"
-#: xpack/plugins/cloud/models.py:186
+#: xpack/plugins/cloud/models.py:165
msgid "Partial succeed"
msgstr ""
-#: xpack/plugins/cloud/models.py:190
-msgid "Result"
-msgstr "结果"
-
-#: xpack/plugins/cloud/models.py:193 xpack/plugins/cloud/models.py:209
+#: xpack/plugins/cloud/models.py:172 xpack/plugins/cloud/models.py:188
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:71
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:68
msgid "Date sync"
msgstr "同步日期"
-#: xpack/plugins/cloud/models.py:200
+#: xpack/plugins/cloud/models.py:179
msgid "Exist"
msgstr "存在"
-#: xpack/plugins/cloud/models.py:203
+#: xpack/plugins/cloud/models.py:182
msgid "Sync task"
msgstr "同步任务"
-#: xpack/plugins/cloud/models.py:204
+#: xpack/plugins/cloud/models.py:183
msgid "Sync instance task history"
msgstr "同步实例任务历史"
-#: xpack/plugins/cloud/models.py:205
+#: xpack/plugins/cloud/models.py:184
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:91
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63
msgid "Instance"
msgstr "实例"
-#: xpack/plugins/cloud/providers/base.py:73
-msgid "任务执行开始: {}"
-msgstr ""
+#: xpack/plugins/cloud/providers/aliyun.py:14
+msgid "Aliyun"
+msgstr "阿里云"
-#: xpack/plugins/cloud/providers/base.py:77
-msgid "检测账户有效性: {}"
-msgstr ""
+#: xpack/plugins/cloud/providers/aws.py:11
+msgid "AWS (China)"
+msgstr "AWS (中国)"
-#: xpack/plugins/cloud/providers/base.py:80
-msgid "账户无效!"
-msgstr ""
+#: xpack/plugins/cloud/providers/aws.py:12
+msgid "AWS (International)"
+msgstr "AWS (国际)"
-#: xpack/plugins/cloud/providers/base.py:85
-msgid "账户有效!"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:91
-msgid "任务执行结束!"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:93
-msgid ""
-"查看任务详细信息路径: XPack -> 云管中心 -> 任务列表 -> 任务详情(点击任务名"
-"称) -> 查看同步历史列表/实例列表"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:130
-msgid "同步实例列表: {}"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:139
-msgid "同步地域列表: {}"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:143
-msgid "地域: {}"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:154
-msgid "实例: {}, 地域: {}"
-msgstr ""
-
-#: xpack/plugins/cloud/providers/base.py:160
-msgid "正在创建资产..."
-msgstr ""
+#: xpack/plugins/cloud/providers/qcloud.py:14
+msgid "Qcloud"
+msgstr "腾讯云"
#: xpack/plugins/cloud/templates/cloud/account_detail.html:22
#: xpack/plugins/cloud/views.py:72
@@ -4562,6 +4605,20 @@ msgstr "创建组织"
msgid "Update org"
msgstr "更新组织"
+#, fuzzy
+#~| msgid "Audits"
+#~ msgid "Audit"
+#~ msgstr "日志审计"
+
+#~ msgid "User id"
+#~ msgstr "用户"
+
+#~ msgid "Start execute"
+#~ msgstr "开始执行"
+
+#~ msgid "Start"
+#~ msgstr "开始"
+
#, fuzzy
#~| msgid "Update setting successfully"
#~ msgid "Update setting successfully, please restart program"
diff --git a/apps/ops/ansible/callback.py b/apps/ops/ansible/callback.py
index 0af872b25..c666ce294 100644
--- a/apps/ops/ansible/callback.py
+++ b/apps/ops/ansible/callback.py
@@ -1,18 +1,16 @@
# ~*~ coding: utf-8 ~*~
-import sys
+import datetime
+from collections import defaultdict
+from ansible import constants as C
from ansible.plugins.callback import CallbackBase
from ansible.plugins.callback.default import CallbackModule
-
-from .display import TeeObj
+from ansible.plugins.callback.minimal import CallbackModule as CMDCallBackModule
-class AdHocResultCallback(CallbackModule):
- """
- Task result Callback
- """
- def __init__(self, display=None, options=None, file_obj=None):
+class CallbackMixin:
+ def __init__(self, display=None):
# result_raw example: {
# "ok": {"hostname": {"task_name": {},...},..},
# "failed": {"hostname": {"task_name": {}..}, ..},
@@ -20,63 +18,129 @@ class AdHocResultCallback(CallbackModule):
# "skipped": {"hostname": {"task_name": {}, ..}, ..},
# }
# results_summary example: {
- # "contacted": {"hostname",...},
+ # "contacted": {"hostname": {"task_name": {}}, "hostname": {}},
# "dark": {"hostname": {"task_name": {}, "task_name": {}},...,},
+ # "success": True
# }
- self.results_raw = dict(ok={}, failed={}, unreachable={}, skipped={})
- self.results_summary = dict(contacted=[], dark={})
+ self.results_raw = dict(
+ ok=defaultdict(dict),
+ failed=defaultdict(dict),
+ unreachable=defaultdict(dict),
+ skippe=defaultdict(dict),
+ )
+ self.results_summary = dict(
+ contacted=defaultdict(dict),
+ dark=defaultdict(dict),
+ success=True
+ )
+ self.results = {
+ 'raw': self.results_raw,
+ 'summary': self.results_summary,
+ }
super().__init__()
- if file_obj is not None:
- sys.stdout = TeeObj(file_obj)
+ if display:
+ self._display = display
+ self._display.columns = 79
- def gather_result(self, t, res):
- self._clean_results(res._result, res._task.action)
- host = res._host.get_name()
- task_name = res.task_name
- task_result = res._result
+ def display(self, msg):
+ self._display.display(msg)
- if self.results_raw[t].get(host):
- self.results_raw[t][host][task_name] = task_result
- else:
- self.results_raw[t][host] = {task_name: task_result}
+ def gather_result(self, t, result):
+ self._clean_results(result._result, result._task.action)
+ host = result._host.get_name()
+ task_name = result.task_name
+ task_result = result._result
+
+ self.results_raw[t][host][task_name] = task_result
self.clean_result(t, host, task_name, task_result)
+
+class AdHocResultCallback(CallbackMixin, CallbackModule, CMDCallBackModule):
+ """
+ Task result Callback
+ """
def clean_result(self, t, host, task_name, task_result):
contacted = self.results_summary["contacted"]
dark = self.results_summary["dark"]
- if t in ("ok", "skipped") and host not in dark:
- if host not in contacted:
- contacted.append(host)
- else:
- if dark.get(host):
- dark[host][task_name] = task_result.values
+
+ if task_result.get('rc') is not None:
+ cmd = task_result.get('cmd')
+ if isinstance(cmd, list):
+ cmd = " ".join(cmd)
else:
- dark[host] = {task_name: task_result}
- if host in contacted:
- contacted.remove(host)
+ cmd = str(cmd)
+ detail = {
+ 'cmd': cmd,
+ 'stderr': task_result.get('stderr'),
+ 'stdout': task_result.get('stdout'),
+ 'rc': task_result.get('rc'),
+ 'delta': task_result.get('delta'),
+ 'msg': task_result.get('msg', '')
+ }
+ else:
+ detail = {
+ "changed": task_result.get('changed', False),
+ "msg": task_result.get('msg', '')
+ }
+
+ if t in ("ok", "skipped"):
+ contacted[host][task_name] = detail
+ else:
+ dark[host][task_name] = detail
def v2_runner_on_failed(self, result, ignore_errors=False):
+ self.results_summary['success'] = False
self.gather_result("failed", result)
- super().v2_runner_on_failed(result, ignore_errors=ignore_errors)
+
+ if result._task.action in C.MODULE_NO_JSON:
+ CMDCallBackModule.v2_runner_on_failed(self,
+ result, ignore_errors=ignore_errors
+ )
+ else:
+ super().v2_runner_on_failed(
+ result, ignore_errors=ignore_errors
+ )
def v2_runner_on_ok(self, result):
self.gather_result("ok", result)
- super().v2_runner_on_ok(result)
+ if result._task.action in C.MODULE_NO_JSON:
+ CMDCallBackModule.v2_runner_on_ok(self, result)
+ else:
+ super().v2_runner_on_ok(result)
def v2_runner_on_skipped(self, result):
self.gather_result("skipped", result)
super().v2_runner_on_skipped(result)
def v2_runner_on_unreachable(self, result):
+ self.results_summary['success'] = False
self.gather_result("unreachable", result)
super().v2_runner_on_unreachable(result)
+ def on_playbook_start(self, name):
+ date_start = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ self.display(
+ "{} Start task: {}\r\n".format(date_start, name)
+ )
+
+ def on_playbook_end(self, name):
+ date_finished = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ self.display(
+ "{} Task finish\r\n".format(date_finished)
+ )
+
+ def display_skipped_hosts(self):
+ pass
+
+ def display_ok_hosts(self):
+ pass
+
class CommandResultCallback(AdHocResultCallback):
"""
Command result callback
"""
- def __init__(self, display=None):
+ def __init__(self, display=None, **kwargs):
# results_command: {
# "cmd": "",
# "stderr": "",
diff --git a/apps/ops/ansible/runner.py b/apps/ops/ansible/runner.py
index 3e168e987..cc48b2447 100644
--- a/apps/ops/ansible/runner.py
+++ b/apps/ops/ansible/runner.py
@@ -17,7 +17,7 @@ from common.utils import get_logger
from .exceptions import AnsibleError
-__all__ = ["AdHocRunner", "PlayBookRunner"]
+__all__ = ["AdHocRunner", "PlayBookRunner", "CommandRunner"]
C.HOST_KEY_CHECKING = False
logger = get_logger(__name__)
@@ -45,7 +45,7 @@ def get_default_options():
listtasks=False,
listhosts=False,
syntax=False,
- timeout=60,
+ timeout=30,
connection='ssh',
module_path='',
forks=10,
@@ -145,7 +145,7 @@ class AdHocRunner:
)
def get_result_callback(self, file_obj=None):
- return self.__class__.results_callback_class(file_obj=file_obj)
+ return self.__class__.results_callback_class()
@staticmethod
def check_module_args(module_name, module_args=''):
@@ -177,17 +177,16 @@ class AdHocRunner:
options = self.__class__.default_options
return options
- def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no', file_obj=None):
+ def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no'):
"""
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
:param pattern: all, *, or others
:param play_name: The play name
:param gather_facts:
- :param file_obj: logging to file_obj
:return:
"""
self.check_pattern(pattern)
- self.results_callback = self.get_result_callback(file_obj)
+ self.results_callback = self.get_result_callback()
cleaned_tasks = self.clean_tasks(tasks)
play_source = dict(
@@ -211,10 +210,6 @@ class AdHocRunner:
stdout_callback=self.results_callback,
passwords=self.options.passwords,
)
- print("Get matched hosts: {}".format(
- self.inventory.get_matched_hosts(pattern)
- ))
-
try:
tqm.run(play)
return self.results_callback
@@ -229,16 +224,14 @@ class CommandRunner(AdHocRunner):
results_callback_class = CommandResultCallback
modules_choices = ('shell', 'raw', 'command', 'script')
- def execute(self, cmd, pattern, module=None):
+ def execute(self, cmd, pattern, module='shell'):
if module and module not in self.modules_choices:
raise AnsibleError("Module should in {}".format(self.modules_choices))
- else:
- module = "shell"
tasks = [
{"action": {"module": module, "args": cmd}}
]
hosts = self.inventory.get_hosts(pattern=pattern)
- name = "Run command {} on {}".format(cmd, ", ".join([host.name for host in hosts]))
+ name = "Run command {} on {}'s hosts".format(cmd, len(hosts))
return self.run(tasks, pattern, play_name=name)
diff --git a/apps/ops/api/__init__.py b/apps/ops/api/__init__.py
new file mode 100644
index 000000000..e59889cd2
--- /dev/null
+++ b/apps/ops/api/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+#
+from .adhoc import *
+from .celery import *
+from .command import *
diff --git a/apps/ops/api.py b/apps/ops/api/adhoc.py
similarity index 57%
rename from apps/ops/api.py
rename to apps/ops/api/adhoc.py
index f052abf4f..e1121a7af 100644
--- a/apps/ops/api.py
+++ b/apps/ops/api/adhoc.py
@@ -1,26 +1,32 @@
-# ~*~ coding: utf-8 ~*~
-import uuid
-import os
+# -*- coding: utf-8 -*-
+#
-from django.core.cache import cache
from django.shortcuts import get_object_or_404
-from django.utils.translation import ugettext as _
from rest_framework import viewsets, generics
from rest_framework.views import Response
from common.permissions import IsOrgAdmin
-from .models import Task, AdHoc, AdHocRunHistory, CeleryTask
-from .serializers import TaskSerializer, AdHocSerializer, \
+from orgs.utils import current_org
+from ..models import Task, AdHoc, AdHocRunHistory
+from ..serializers import TaskSerializer, AdHocSerializer, \
AdHocRunHistorySerializer
-from .tasks import run_ansible_task
+from ..tasks import run_ansible_task
+
+__all__ = [
+ 'TaskViewSet', 'TaskRun', 'AdHocViewSet', 'AdHocRunHistoryViewSet'
+]
class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
permission_classes = (IsOrgAdmin,)
- # label = None
- # help_text = ''
+
+ def get_queryset(self):
+ queryset = super().get_queryset()
+ if current_org:
+ queryset = queryset.filter(created_by=current_org.id)
+ return queryset
class TaskRun(generics.RetrieveAPIView):
@@ -47,7 +53,7 @@ class AdHocViewSet(viewsets.ModelViewSet):
return self.queryset
-class AdHocRunHistorySet(viewsets.ModelViewSet):
+class AdHocRunHistoryViewSet(viewsets.ModelViewSet):
queryset = AdHocRunHistory.objects.all()
serializer_class = AdHocRunHistorySerializer
permission_classes = (IsOrgAdmin,)
@@ -66,28 +72,6 @@ class AdHocRunHistorySet(viewsets.ModelViewSet):
return self.queryset
-class CeleryTaskLogApi(generics.RetrieveAPIView):
- permission_classes = (IsOrgAdmin,)
- buff_size = 1024 * 10
- end = False
- queryset = CeleryTask.objects.all()
- def get(self, request, *args, **kwargs):
- mark = request.query_params.get("mark") or str(uuid.uuid4())
- task = self.get_object()
- log_path = task.full_log_path
- if not log_path or not os.path.isfile(log_path):
- return Response({"data": _("Waiting ...")}, status=203)
-
- with open(log_path, 'r') as f:
- offset = cache.get(mark, 0)
- f.seek(offset)
- data = f.read(self.buff_size).replace('\n', '\r\n')
- mark = str(uuid.uuid4())
- cache.set(mark, f.tell(), 5)
-
- if data == '' and task.is_finished():
- self.end = True
- return Response({"data": data, 'end': self.end, 'mark': mark})
diff --git a/apps/ops/api/celery.py b/apps/ops/api/celery.py
new file mode 100644
index 000000000..2640cffec
--- /dev/null
+++ b/apps/ops/api/celery.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+#
+import uuid
+import os
+
+from celery.result import AsyncResult
+from django.core.cache import cache
+from django.utils.translation import ugettext as _
+from rest_framework import generics
+from rest_framework.views import Response
+
+from common.permissions import IsOrgAdmin, IsValidUser
+from ..models import CeleryTask
+from ..serializers import CeleryResultSerializer
+
+
+__all__ = ['CeleryTaskLogApi', 'CeleryResultApi']
+
+
+class CeleryTaskLogApi(generics.RetrieveAPIView):
+ permission_classes = (IsValidUser,)
+ buff_size = 1024 * 10
+ end = False
+ queryset = CeleryTask.objects.all()
+
+ def get(self, request, *args, **kwargs):
+ mark = request.query_params.get("mark") or str(uuid.uuid4())
+ task = self.get_object()
+ log_path = task.full_log_path
+
+ if not log_path or not os.path.isfile(log_path):
+ return Response({"data": _("Waiting ...")}, status=203)
+
+ with open(log_path, 'r') as f:
+ offset = cache.get(mark, 0)
+ f.seek(offset)
+ data = f.read(self.buff_size).replace('\n', '\r\n')
+ mark = str(uuid.uuid4())
+ cache.set(mark, f.tell(), 5)
+
+ if data == '' and task.is_finished():
+ self.end = True
+ return Response({"data": data, 'end': self.end, 'mark': mark})
+
+
+class CeleryResultApi(generics.RetrieveAPIView):
+ permission_classes = (IsValidUser,)
+ serializer_class = CeleryResultSerializer
+
+ def get_object(self):
+ pk = self.kwargs.get('pk')
+ return AsyncResult(pk)
+
diff --git a/apps/ops/api/command.py b/apps/ops/api/command.py
new file mode 100644
index 000000000..9d83d1464
--- /dev/null
+++ b/apps/ops/api/command.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+#
+from rest_framework import viewsets
+
+from common.permissions import IsValidUser
+from ..models import CommandExecution
+from ..serializers import CommandExecutionSerializer
+from ..tasks import run_command_execution
+
+
+class CommandExecutionViewSet(viewsets.ModelViewSet):
+ serializer_class = CommandExecutionSerializer
+ permission_classes = (IsValidUser,)
+ task = None
+
+ def get_queryset(self):
+ return CommandExecution.objects.filter(
+ user_id=str(self.request.user.id)
+ )
+
+ def perform_create(self, serializer):
+ instance = serializer.save()
+ instance.user = self.request.user
+ instance.save()
+ run_command_execution.apply_async(
+ args=(instance.id,), task_id=str(instance.id)
+ )
diff --git a/apps/ops/celery/signal_handler.py b/apps/ops/celery/signal_handler.py
index c64befbb7..961c18ad3 100644
--- a/apps/ops/celery/signal_handler.py
+++ b/apps/ops/celery/signal_handler.py
@@ -27,7 +27,6 @@ def on_app_ready(sender=None, headers=None, body=None, **kwargs):
if cache.get("CELERY_APP_READY", 0) == 1:
return
cache.set("CELERY_APP_READY", 1, 10)
- logger.debug("App ready signal recv")
tasks = get_after_app_ready_tasks()
logger.debug("Start need start task: [{}]".format(
", ".join(tasks))
diff --git a/apps/ops/forms.py b/apps/ops/forms.py
new file mode 100644
index 000000000..6658980f8
--- /dev/null
+++ b/apps/ops/forms.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+#
+from django import forms
+
+from assets.models import SystemUser
+from .models import CommandExecution
+
+
+class CommandExecutionForm(forms.ModelForm):
+ class Meta:
+ model = CommandExecution
+ fields = ['run_as', 'command']
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ run_as_field = self.fields.get('run_as')
+ run_as_field.queryset = SystemUser.objects.all()
diff --git a/apps/ops/inventory.py b/apps/ops/inventory.py
index 5b5e98551..7e21d156d 100644
--- a/apps/ops/inventory.py
+++ b/apps/ops/inventory.py
@@ -2,7 +2,7 @@
#
from .ansible.inventory import BaseInventory
-from assets.utils import get_assets_by_fullname_list, get_system_user_by_name
+from assets.utils import get_assets_by_id_list, get_system_user_by_id
__all__ = [
'JMSInventory'
@@ -14,19 +14,18 @@ class JMSInventory(BaseInventory):
JMS Inventory is the manager with jumpserver assets, so you can
write you own manager, construct you inventory
"""
- def __init__(self, hostname_list, run_as_admin=False, run_as=None, become_info=None):
+ def __init__(self, assets, run_as_admin=False, run_as=None, become_info=None):
"""
- :param hostname_list: ["test1", ]
+ :param host_id_list: ["test1", ]
:param run_as_admin: True 是否使用管理用户去执行, 每台服务器的管理用户可能不同
:param run_as: 是否统一使用某个系统用户去执行
:param become_info: 是否become成某个用户去执行
"""
- self.hostname_list = hostname_list
+ self.assets = assets
self.using_admin = run_as_admin
self.run_as = run_as
self.become_info = become_info
- assets = self.get_jms_assets()
host_list = []
for asset in assets:
@@ -43,14 +42,10 @@ class JMSInventory(BaseInventory):
host.update(become_info)
super().__init__(host_list=host_list)
- def get_jms_assets(self):
- assets = get_assets_by_fullname_list(self.hostname_list)
- return assets
-
def convert_to_ansible(self, asset, run_as_admin=False):
info = {
'id': asset.id,
- 'hostname': asset.fullname,
+ 'hostname': asset.hostname,
'ip': asset.ip,
'port': asset.port,
'vars': dict(),
@@ -75,7 +70,7 @@ class JMSInventory(BaseInventory):
return info
def get_run_user_info(self):
- system_user = get_system_user_by_name(self.run_as)
+ system_user = self.run_as
if not system_user:
return {}
else:
diff --git a/apps/ops/migrations/0003_auto_20181207_1744.py b/apps/ops/migrations/0003_auto_20181207_1744.py
new file mode 100644
index 000000000..d3ef032e9
--- /dev/null
+++ b/apps/ops/migrations/0003_auto_20181207_1744.py
@@ -0,0 +1,56 @@
+# Generated by Django 2.1.4 on 2018-12-07 09:44
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('assets', '0023_auto_20181016_1650'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('ops', '0002_celerytask'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='CommandExecution',
+ fields=[
+ ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
+ ('command', models.TextField(verbose_name='Command')),
+ ('_result', models.TextField(blank=True, null=True, verbose_name='Result')),
+ ('is_finished', models.BooleanField(default=False)),
+ ('date_created', models.DateTimeField(auto_now_add=True)),
+ ('date_start', models.DateTimeField(null=True)),
+ ('date_finished', models.DateTimeField(null=True)),
+ ('hosts', models.ManyToManyField(to='assets.Asset')),
+ ('run_as', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser')),
+ ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.RemoveField(
+ model_name='adhoc',
+ name='run_as',
+ ),
+ migrations.AddField(
+ model_name='adhoc',
+ name='hosts',
+ field=models.ManyToManyField(to='assets.Asset', verbose_name='Host'),
+ ),
+ migrations.AlterField(
+ model_name='task',
+ name='created_by',
+ field=models.CharField(blank=True, default='', max_length=128),
+ ),
+ migrations.AlterField(
+ model_name='task',
+ name='name',
+ field=models.CharField(max_length=128, verbose_name='Name'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='task',
+ unique_together={('name', 'created_by')},
+ ),
+ ]
diff --git a/apps/ops/migrations/0004_adhoc_run_as.py b/apps/ops/migrations/0004_adhoc_run_as.py
new file mode 100644
index 000000000..8e49eaa2b
--- /dev/null
+++ b/apps/ops/migrations/0004_adhoc_run_as.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.1.4 on 2018-12-07 09:44
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('assets', '0023_auto_20181016_1650'),
+ ('ops', '0003_auto_20181207_1744'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='adhoc',
+ name='run_as',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser'),
+ ),
+ ]
diff --git a/apps/ops/models/__init__.py b/apps/ops/models/__init__.py
index 68920eb42..0a9ed463c 100644
--- a/apps/ops/models/__init__.py
+++ b/apps/ops/models/__init__.py
@@ -2,4 +2,5 @@
#
from .adhoc import *
-from .celery import *
\ No newline at end of file
+from .celery import *
+from .command import *
diff --git a/apps/ops/models/adhoc.py b/apps/ops/models/adhoc.py
index 187790b62..1f322f944 100644
--- a/apps/ops/models/adhoc.py
+++ b/apps/ops/models/adhoc.py
@@ -34,16 +34,17 @@ class Task(models.Model):
One task can have some versions of adhoc, run a task only run the latest version adhoc
"""
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
- name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
+ name = models.CharField(max_length=128, verbose_name=_('Name'))
interval = models.IntegerField(verbose_name=_("Interval"), null=True, blank=True, help_text=_("Units: seconds"))
crontab = models.CharField(verbose_name=_("Crontab"), null=True, blank=True, max_length=128, help_text=_("5 * * * *"))
is_periodic = models.BooleanField(default=False)
callback = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Callback")) # Callback must be a registered celery task
is_deleted = models.BooleanField(default=False)
comment = models.TextField(blank=True, verbose_name=_("Comment"))
- created_by = models.CharField(max_length=128, blank=True, null=True, default='')
+ created_by = models.CharField(max_length=128, blank=True, default='')
date_created = models.DateTimeField(auto_now_add=True)
__latest_adhoc = None
+ _ignore_auto_created_by = True
@property
def short_id(self):
@@ -94,7 +95,7 @@ class Task(models.Model):
update_fields=None):
from ..tasks import run_ansible_task
super().save(
- force_insert=force_insert, force_update=force_update,
+ force_insert=force_insert, force_update=force_update,
using=using, update_fields=update_fields,
)
@@ -108,7 +109,7 @@ class Task(models.Model):
crontab = self.crontab
tasks = {
- self.name: {
+ self.__str__(): {
"task": run_ansible_task.name,
"interval": interval,
"crontab": crontab,
@@ -119,11 +120,11 @@ class Task(models.Model):
}
create_or_update_celery_periodic_tasks(tasks)
else:
- disable_celery_periodic_task(self.name)
+ disable_celery_periodic_task(self.__str__())
def delete(self, using=None, keep_parents=False):
super().delete(using=using, keep_parents=keep_parents)
- delete_celery_periodic_task(self.name)
+ delete_celery_periodic_task(self.__str__())
@property
def schedule(self):
@@ -133,10 +134,11 @@ class Task(models.Model):
return None
def __str__(self):
- return self.name
+ return self.name + '@' + str(self.created_by)
class Meta:
db_table = 'ops_task'
+ unique_together = ('name', 'created_by')
get_latest_by = 'date_created'
@@ -157,8 +159,9 @@ class AdHoc(models.Model):
pattern = models.CharField(max_length=64, default='{}', verbose_name=_('Pattern'))
_options = models.CharField(max_length=1024, default='', verbose_name=_('Options'))
_hosts = models.TextField(blank=True, verbose_name=_('Hosts')) # ['hostname1', 'hostname2']
+ hosts = models.ManyToManyField('assets.Asset', verbose_name=_("Host"))
run_as_admin = models.BooleanField(default=False, verbose_name=_('Run as admin'))
- run_as = models.CharField(max_length=128, default='', verbose_name=_("Run as"))
+ run_as = models.ForeignKey('assets.SystemUser', null=True, on_delete=models.CASCADE)
_become = models.CharField(max_length=1024, default='', verbose_name=_("Become"))
created_by = models.CharField(max_length=64, default='', null=True, verbose_name=_('Create by'))
date_created = models.DateTimeField(auto_now_add=True)
@@ -174,14 +177,6 @@ class AdHoc(models.Model):
else:
raise SyntaxError('Tasks should be a list: {}'.format(item))
- @property
- def hosts(self):
- return json.loads(self._hosts)
-
- @hosts.setter
- def hosts(self, item):
- self._hosts = json.dumps(item)
-
@property
def inventory(self):
if self.become:
@@ -194,7 +189,7 @@ class AdHoc(models.Model):
become_info = None
inventory = JMSInventory(
- self.hosts, run_as_admin=self.run_as_admin,
+ self.hosts.all(), run_as_admin=self.run_as_admin,
run_as=self.run_as, become_info=become_info
)
return inventory
@@ -242,14 +237,13 @@ class AdHoc(models.Model):
history.timedelta = time.time() - time_start
history.save()
- def _run_only(self, file_obj=None):
+ def _run_only(self):
runner = AdHocRunner(self.inventory, options=self.options)
try:
result = runner.run(
self.tasks,
self.pattern,
self.task.name,
- file_obj=file_obj,
)
return result.results_raw, result.results_summary
except AnsibleError as e:
diff --git a/apps/ops/models/command.py b/apps/ops/models/command.py
new file mode 100644
index 000000000..b2639c6ff
--- /dev/null
+++ b/apps/ops/models/command.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+#
+import uuid
+import json
+
+from django.utils import timezone
+from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ugettext
+from django.db import models
+
+from ..ansible.runner import CommandRunner
+from ..inventory import JMSInventory
+
+
+class CommandExecution(models.Model):
+ id = models.UUIDField(default=uuid.uuid4, primary_key=True)
+ hosts = models.ManyToManyField('assets.Asset')
+ run_as = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE)
+ command = models.TextField(verbose_name=_("Command"))
+ _result = models.TextField(blank=True, null=True, verbose_name=_('Result'))
+ user = models.ForeignKey('users.User', on_delete=models.CASCADE, null=True)
+ is_finished = models.BooleanField(default=False)
+ date_created = models.DateTimeField(auto_now_add=True)
+ date_start = models.DateTimeField(null=True)
+ date_finished = models.DateTimeField(null=True)
+
+ def __str__(self):
+ return self.command[:10]
+
+ @property
+ def inventory(self):
+ return JMSInventory(self.hosts.all(), run_as=self.run_as)
+
+ @property
+ def result(self):
+ if self._result:
+ return json.loads(self._result)
+ else:
+ return {}
+
+ @result.setter
+ def result(self, item):
+ self._result = json.dumps(item)
+
+ @property
+ def is_success(self):
+ if 'error' in self.result:
+ return False
+ return True
+
+ def run(self):
+ print('-'*10 + ' ' + ugettext('Task start') + ' ' + '-'*10)
+ self.date_start = timezone.now()
+ ok, msg = self.run_as.is_command_can_run(self.command)
+ if ok:
+ runner = CommandRunner(self.inventory)
+ try:
+ result = runner.execute(self.command, 'all')
+ self.result = result.results_command
+ except Exception as e:
+ print("Error occur: {}".format(e))
+ self.result = {"error": str(e)}
+ else:
+ msg = _("Command `{}` is forbidden ........").format(self.command)
+ print('\033[31m' + msg + '\033[0m')
+ self.result = {"error": msg}
+ self.is_finished = True
+ self.date_finished = timezone.now()
+ self.save()
+ print('-'*10 + ' ' + ugettext('Task end') + ' ' + '-'*10)
+ return self.result
diff --git a/apps/ops/serializers.py b/apps/ops/serializers.py
index a395a427e..13423486f 100644
--- a/apps/ops/serializers.py
+++ b/apps/ops/serializers.py
@@ -1,8 +1,19 @@
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from rest_framework import serializers
+from django.shortcuts import reverse
-from .models import Task, AdHoc, AdHocRunHistory
+from .models import Task, AdHoc, AdHocRunHistory, CommandExecution
+
+
+class CeleryResultSerializer(serializers.Serializer):
+ id = serializers.UUIDField()
+ result = serializers.JSONField()
+ state = serializers.CharField(max_length=16)
+
+
+class CeleryTaskSerializer(serializers.Serializer):
+ pass
class TaskSerializer(serializers.ModelSerializer):
@@ -51,3 +62,23 @@ class AdHocRunHistorySerializer(serializers.ModelSerializer):
fields = super().get_field_names(declared_fields, info)
fields.extend(['summary', 'short_id'])
return fields
+
+
+class CommandExecutionSerializer(serializers.ModelSerializer):
+ result = serializers.JSONField(read_only=True)
+ log_url = serializers.SerializerMethodField()
+
+ class Meta:
+ model = CommandExecution
+ fields = [
+ 'id', 'hosts', 'run_as', 'command', 'result', 'log_url',
+ 'is_finished', 'date_created', 'date_finished'
+ ]
+ read_only_fields = [
+ 'id', 'result', 'is_finished', 'log_url', 'date_created',
+ 'date_finished'
+ ]
+
+ @staticmethod
+ def get_log_url(obj):
+ return reverse('api-ops:celery-task-log', kwargs={'pk': obj.id})
diff --git a/apps/ops/tasks.py b/apps/ops/tasks.py
index 8df803207..bcdb09cee 100644
--- a/apps/ops/tasks.py
+++ b/apps/ops/tasks.py
@@ -2,7 +2,7 @@
from celery import shared_task, subtask
from common.utils import get_logger, get_object_or_none
-from .models import Task
+from .models import Task, CommandExecution
logger = get_logger(__file__)
@@ -28,6 +28,12 @@ def run_ansible_task(tid, callback=None, **kwargs):
logger.error("No task found")
+@shared_task
+def run_command_execution(cid, **kwargs):
+ execution = get_object_or_none(CommandExecution, id=cid)
+ return execution.run()
+
+
@shared_task
def hello(name, callback=None):
print("Hello {}".format(name))
diff --git a/apps/ops/templates/ops/celery_task_log.html b/apps/ops/templates/ops/celery_task_log.html
index 13885c2cc..66b3177c7 100644
--- a/apps/ops/templates/ops/celery_task_log.html
+++ b/apps/ops/templates/ops/celery_task_log.html
@@ -27,6 +27,7 @@
var end = false;
var error = false;
var interval = 200;
+ var success = true;
function calWinSize() {
var t = $('#marker');
@@ -34,20 +35,19 @@
{#colWidth = 1.00 * t.width() / 6;#}
}
function resize() {
- {#console.log(rowHeight, window.innerHeight);#}
- {#console.log(colWidth, window.innerWidth);#}
var rows = Math.floor(window.innerHeight / rowHeight) - 1;
var cols = Math.floor(window.innerWidth / colWidth) - 2;
- console.log(rows, cols);
term.resize(cols, rows);
}
function requestAndWrite() {
- if (!end) {
+ if (!end && success) {
+ success = false;
$.ajax({
url: url + '?mark=' + mark,
method: "GET",
contentType: "application/json; charset=utf-8"
}).done(function(data, textStatue, jqXHR) {
+ success = true;
if (jqXHR.status === 203) {
error = true;
term.write('.');
@@ -64,7 +64,14 @@
}
}
$(document).ready(function () {
- term = new Terminal();
+ term = new Terminal({
+ cursorBlink: false,
+ screenKeys: false,
+ fontFamily: '"Monaco", "Consolas", "monospace"',
+ fontSize: 12,
+ rightClickSelectsWord: true,
+ disableStdin: true
+ });
term.open(document.getElementById('term'));
term.resize(80, 24);
resize();
diff --git a/apps/ops/templates/ops/command_execution_create.html b/apps/ops/templates/ops/command_execution_create.html
new file mode 100644
index 000000000..250acc4ea
--- /dev/null
+++ b/apps/ops/templates/ops/command_execution_create.html
@@ -0,0 +1,254 @@
+{% extends 'base.html' %}
+{% load static %}
+{% load i18n %}
+{% load bootstrap3 %}
+
+{% block custom_head_css_js %}
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+
+{% block content %}
+
+{% endblock %}
+
+{% block custom_foot_js %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/apps/ops/templates/ops/command_execution_list.html b/apps/ops/templates/ops/command_execution_list.html
new file mode 100644
index 000000000..542847b73
--- /dev/null
+++ b/apps/ops/templates/ops/command_execution_list.html
@@ -0,0 +1,95 @@
+{% extends '_base_list.html' %}
+{% load i18n %}
+{% load static %}
+{% load common_tags %}
+
+{% block content_left_head %}
+{% endblock %}
+
+{% block table_search %}
+
+{% endblock %}
+
+{% block table_head %}
+
+
{% trans 'Hosts' %}
+
{% trans 'User' %}
+
{% trans 'Command' %}
+
{% trans 'Output' %}
+
{% trans 'Finished' %}
+
{% trans 'Success' %}
+
{% trans 'Date start' %}
+
{% trans 'Date finished' %}
+{% endblock %}
+
+{% block table_body %}
+ {% for object in object_list %}
+
+
+ {{ object.hosts.count }}
+ {{ object.user }}
+ {{ object.command| truncatechars:16 }}
+ 查看
+ {{ object.is_finished | state_show | safe }}
+ {{ object.is_success | state_show | safe }}
+ {{ object.date_start }}
+ {{ object.date_finished }}
+
+ {% endfor %}
+{% endblock %}
+
+{% block custom_foot_js %}
+
+
+{% endblock %}
+
diff --git a/apps/ops/templates/ops/task_detail.html b/apps/ops/templates/ops/task_detail.html
index cd39d0a2c..d8f9520be 100644
--- a/apps/ops/templates/ops/task_detail.html
+++ b/apps/ops/templates/ops/task_detail.html
@@ -4,10 +4,11 @@
{% block custom_head_css_js %}
-
+
-
+
{% endblock %}
+
{% block content %}
diff --git a/apps/ops/urls/api_urls.py b/apps/ops/urls/api_urls.py
index d1e815800..615f53a8b 100644
--- a/apps/ops/urls/api_urls.py
+++ b/apps/ops/urls/api_urls.py
@@ -11,11 +11,12 @@ app_name = "ops"
router = DefaultRouter()
router.register(r'tasks', api.TaskViewSet, 'task')
router.register(r'adhoc', api.AdHocViewSet, 'adhoc')
-router.register(r'history', api.AdHocRunHistorySet, 'history')
+router.register(r'command-executions', api.CommandExecutionViewSet, 'command-execution')
urlpatterns = [
path('tasks/
/run/', api.TaskRun.as_view(), name='task-run'),
path('celery/task//log/', api.CeleryTaskLogApi.as_view(), name='celery-task-log'),
+ path('celery/task//result/', api.CeleryResultApi.as_view(), name='celery-result'),
]
urlpatterns += router.urls
diff --git a/apps/ops/urls/view_urls.py b/apps/ops/urls/view_urls.py
index f49506e80..f8428a667 100644
--- a/apps/ops/urls/view_urls.py
+++ b/apps/ops/urls/view_urls.py
@@ -18,4 +18,7 @@ urlpatterns = [
path('adhoc//history/', views.AdHocHistoryView.as_view(), name='adhoc-history'),
path('adhoc/history//', views.AdHocHistoryDetailView.as_view(), name='adhoc-history-detail'),
path('celery/task//log/', views.CeleryTaskLogView.as_view(), name='celery-task-log'),
+
+ path('command-execution/', views.CommandExecutionListView.as_view(), name='command-execution-list'),
+ path('command-execution/start/', views.CommandExecutionStartView.as_view(), name='command-execution-start'),
]
diff --git a/apps/ops/utils.py b/apps/ops/utils.py
index 55862dd44..d52f9c743 100644
--- a/apps/ops/utils.py
+++ b/apps/ops/utils.py
@@ -1,5 +1,7 @@
# ~*~ coding: utf-8 ~*~
+from django.utils.translation import ugettext_lazy as _
from common.utils import get_logger, get_object_or_none
+from orgs.utils import set_to_root_org
from .models import Task, AdHoc
logger = get_logger(__file__)
@@ -10,15 +12,14 @@ def get_task_by_id(task_id):
def update_or_create_ansible_task(
- task_name, hosts, tasks,
+ task_name, hosts, tasks, created_by,
interval=None, crontab=None, is_periodic=False,
callback=None, pattern='all', options=None,
- run_as_admin=False, run_as="", become_info=None,
- created_by=None,
+ run_as_admin=False, run_as=None, become_info=None,
):
if not hosts or not tasks or not task_name:
return
-
+ set_to_root_org()
defaults = {
'name': task_name,
'interval': interval,
@@ -29,22 +30,27 @@ def update_or_create_ansible_task(
}
created = False
- task, _ = Task.objects.update_or_create(
- defaults=defaults, name=task_name,
+ task, ok = Task.objects.update_or_create(
+ defaults=defaults, name=task_name, created_by=created_by
)
-
- adhoc = task.latest_adhoc
+ adhoc = task.get_latest_adhoc()
new_adhoc = AdHoc(task=task, pattern=pattern,
run_as_admin=run_as_admin,
run_as=run_as)
- new_adhoc.hosts = hosts
new_adhoc.tasks = tasks
new_adhoc.options = options
new_adhoc.become = become_info
- if not adhoc or adhoc != new_adhoc:
- print("Task create new adhoc: {}".format(task_name))
+ hosts_same = True
+ if adhoc:
+ old_hosts = set([str(asset.id) for asset in adhoc.hosts.all()])
+ new_hosts = set([str(asset.id) for asset in hosts])
+ hosts_same = old_hosts == new_hosts
+
+ if not adhoc or adhoc != new_adhoc or not hosts_same:
+ logger.info(_("Update task content: {}").format(task_name))
new_adhoc.save()
+ new_adhoc.hosts.set(hosts)
task.latest_adhoc = new_adhoc
created = True
return task, created
diff --git a/apps/ops/views/__init__.py b/apps/ops/views/__init__.py
new file mode 100644
index 000000000..58bb835a6
--- /dev/null
+++ b/apps/ops/views/__init__.py
@@ -0,0 +1,3 @@
+from .adhoc import *
+from .celery import *
+from .command import *
\ No newline at end of file
diff --git a/apps/ops/views.py b/apps/ops/views/adhoc.py
similarity index 68%
rename from apps/ops/views.py
rename to apps/ops/views/adhoc.py
index 1bbfbfc23..737047290 100644
--- a/apps/ops/views.py
+++ b/apps/ops/views/adhoc.py
@@ -2,14 +2,22 @@
from django.utils.translation import ugettext as _
from django.conf import settings
-from django.views.generic import ListView, DetailView, TemplateView
+from django.views.generic import ListView, DetailView
from common.mixins import DatetimeSearchMixin
-from .models import Task, AdHoc, AdHocRunHistory, CeleryTask
-from common.permissions import SuperUserRequiredMixin, AdminUserRequiredMixin
+from common.permissions import AdminUserRequiredMixin
+from orgs.utils import current_org
+from ..models import Task, AdHoc, AdHocRunHistory
-class TaskListView(SuperUserRequiredMixin, DatetimeSearchMixin, ListView):
+__all__ = [
+ 'TaskListView', 'TaskDetailView', 'TaskHistoryView',
+ 'TaskAdhocView', 'AdHocDetailView', 'AdHocHistoryDetailView',
+ 'AdHocHistoryView'
+]
+
+
+class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
paginate_by = settings.DISPLAY_PER_PAGE
model = Task
ordering = ('-date_created',)
@@ -18,18 +26,23 @@ class TaskListView(SuperUserRequiredMixin, DatetimeSearchMixin, ListView):
keyword = ''
def get_queryset(self):
- self.queryset = super().get_queryset()
+ queryset = super().get_queryset()
+ if current_org.is_real():
+ queryset = queryset.filter(created_by=current_org.id)
+ else:
+ queryset = queryset.filter(created_by='')
+
self.keyword = self.request.GET.get('keyword', '')
- self.queryset = self.queryset.filter(
+ queryset = queryset.filter(
date_created__gt=self.date_from,
date_created__lt=self.date_to
)
if self.keyword:
- self.queryset = self.queryset.filter(
+ queryset = queryset.filter(
name__icontains=self.keyword,
)
- return self.queryset
+ return queryset
def get_context_data(self, **kwargs):
context = {
@@ -43,10 +56,16 @@ class TaskListView(SuperUserRequiredMixin, DatetimeSearchMixin, ListView):
return super().get_context_data(**kwargs)
-class TaskDetailView(SuperUserRequiredMixin, DetailView):
+class TaskDetailView(AdminUserRequiredMixin, DetailView):
model = Task
template_name = 'ops/task_detail.html'
+ def get_queryset(self):
+ queryset = super().get_queryset()
+ if current_org:
+ queryset = queryset.filter(created_by=current_org.id)
+ return queryset
+
def get_context_data(self, **kwargs):
context = {
'app': _('Ops'),
@@ -56,7 +75,7 @@ class TaskDetailView(SuperUserRequiredMixin, DetailView):
return super().get_context_data(**kwargs)
-class TaskAdhocView(SuperUserRequiredMixin, DetailView):
+class TaskAdhocView(AdminUserRequiredMixin, DetailView):
model = Task
template_name = 'ops/task_adhoc.html'
@@ -69,7 +88,7 @@ class TaskAdhocView(SuperUserRequiredMixin, DetailView):
return super().get_context_data(**kwargs)
-class TaskHistoryView(SuperUserRequiredMixin, DetailView):
+class TaskHistoryView(AdminUserRequiredMixin, DetailView):
model = Task
template_name = 'ops/task_history.html'
@@ -82,7 +101,7 @@ class TaskHistoryView(SuperUserRequiredMixin, DetailView):
return super().get_context_data(**kwargs)
-class AdHocDetailView(SuperUserRequiredMixin, DetailView):
+class AdHocDetailView(AdminUserRequiredMixin, DetailView):
model = AdHoc
template_name = 'ops/adhoc_detail.html'
@@ -95,7 +114,7 @@ class AdHocDetailView(SuperUserRequiredMixin, DetailView):
return super().get_context_data(**kwargs)
-class AdHocHistoryView(SuperUserRequiredMixin, DetailView):
+class AdHocHistoryView(AdminUserRequiredMixin, DetailView):
model = AdHoc
template_name = 'ops/adhoc_history.html'
@@ -108,7 +127,7 @@ class AdHocHistoryView(SuperUserRequiredMixin, DetailView):
return super().get_context_data(**kwargs)
-class AdHocHistoryDetailView(SuperUserRequiredMixin, DetailView):
+class AdHocHistoryDetailView(AdminUserRequiredMixin, DetailView):
model = AdHocRunHistory
template_name = 'ops/adhoc_history_detail.html'
@@ -121,6 +140,5 @@ class AdHocHistoryDetailView(SuperUserRequiredMixin, DetailView):
return super().get_context_data(**kwargs)
-class CeleryTaskLogView(AdminUserRequiredMixin, DetailView):
- template_name = 'ops/celery_task_log.html'
- model = CeleryTask
+
+
diff --git a/apps/ops/views/celery.py b/apps/ops/views/celery.py
new file mode 100644
index 000000000..f3da0b17b
--- /dev/null
+++ b/apps/ops/views/celery.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+#
+from django.views.generic import DetailView
+
+from common.permissions import AdminUserRequiredMixin
+from ..models import CeleryTask
+
+
+__all__ = ['CeleryTaskLogView']
+
+
+class CeleryTaskLogView(AdminUserRequiredMixin, DetailView):
+ template_name = 'ops/celery_task_log.html'
+ model = CeleryTask
diff --git a/apps/ops/views/command.py b/apps/ops/views/command.py
new file mode 100644
index 000000000..1c495e44a
--- /dev/null
+++ b/apps/ops/views/command.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+#
+
+from django.utils.translation import ugettext as _
+from django.conf import settings
+from django.views.generic import ListView, TemplateView
+
+from common.mixins import DatetimeSearchMixin
+from ..models import CommandExecution
+from ..forms import CommandExecutionForm
+
+
+__all__ = [
+ 'CommandExecutionListView', 'CommandExecutionStartView'
+]
+
+
+class CommandExecutionListView(DatetimeSearchMixin, ListView):
+ template_name = 'ops/command_execution_list.html'
+ model = CommandExecution
+ paginate_by = settings.DISPLAY_PER_PAGE
+ ordering = ('-date_created',)
+ context_object_name = 'task_list'
+ keyword = ''
+
+ def _get_queryset(self):
+ self.keyword = self.request.GET.get('keyword', '')
+ queryset = super().get_queryset()
+ if self.date_from:
+ queryset = queryset.filter(date_start__gte=self.date_from)
+ if self.date_to:
+ queryset = queryset.filter(date_start__lte=self.date_to)
+ if self.keyword:
+ queryset = queryset.filter(command__icontains=self.keyword)
+ return queryset
+
+ def get_queryset(self):
+ queryset = self._get_queryset().filter(user=self.request.user)
+ return queryset
+
+ def get_context_data(self, **kwargs):
+ context = {
+ 'app': _('Ops'),
+ 'action': _('Command execution list'),
+ 'date_from': self.date_from,
+ 'date_to': self.date_to,
+ 'keyword': self.keyword,
+ }
+ kwargs.update(context)
+ return super().get_context_data(**kwargs)
+
+
+class CommandExecutionStartView(TemplateView):
+ template_name = 'ops/command_execution_create.html'
+ form_class = CommandExecutionForm
+
+ def get_user_system_users(self):
+ from perms.utils import AssetPermissionUtil
+ user = self.request.user
+ util = AssetPermissionUtil(user)
+ system_users = [s for s in util.get_system_users() if s.protocol == 'ssh']
+ return system_users
+
+ def get_context_data(self, **kwargs):
+ system_users = self.get_user_system_users()
+ context = {
+ 'app': _('Ops'),
+ 'action': _('Command execution'),
+ 'form': self.get_form(),
+ 'system_users': system_users
+ }
+ kwargs.update(context)
+ return super().get_context_data(**kwargs)
+
+ def get_form(self):
+ return self.form_class()
diff --git a/apps/perms/api.py b/apps/perms/api.py
index 98287212f..37497e2f1 100644
--- a/apps/perms/api.py
+++ b/apps/perms/api.py
@@ -3,18 +3,20 @@
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView, Response
-from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView
+from rest_framework.generics import ListAPIView, get_object_or_404, \
+ RetrieveUpdateAPIView
from rest_framework import viewsets
from rest_framework.pagination import LimitOffsetPagination
from common.utils import set_or_append_attr_bulk
from common.permissions import IsValidUser, IsOrgAdmin, IsOrgAdminOrAppUser
+from common.tree import TreeNode, TreeNodeSerializer
from orgs.mixins import RootOrgViewMixin
+from orgs.utils import set_to_root_org
from .utils import AssetPermissionUtil
from .models import AssetPermission
from .hands import AssetGrantedSerializer, User, UserGroup, Asset, Node, \
NodeGrantedSerializer, SystemUser, NodeSerializer
-from orgs.utils import set_to_root_org
from . import serializers
from .mixins import AssetsFilterMixin
@@ -25,6 +27,7 @@ __all__ = [
'UserGroupGrantedNodesApi', 'UserGroupGrantedNodesWithAssetsApi', 'UserGroupGrantedNodeAssetsApi',
'ValidateUserAssetPermissionApi', 'AssetPermissionRemoveUserApi', 'AssetPermissionAddUserApi',
'AssetPermissionRemoveAssetApi', 'AssetPermissionAddAssetApi', 'UserGrantedNodeChildrenApi',
+ 'UserGrantedNodesWithAssetsAsTreeApi',
]
@@ -186,6 +189,99 @@ class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView):
return super().get_permissions()
+class UserGrantedNodesWithAssetsAsTreeApi(ListAPIView):
+ serializer_class = TreeNodeSerializer
+ permission_classes = (IsOrgAdminOrAppUser,)
+ show_assets = True
+ system_user_id = None
+
+ def change_org_if_need(self):
+ if self.request.user.is_superuser or \
+ self.request.user.is_app or \
+ self.kwargs.get('pk') is None:
+ set_to_root_org()
+
+ def get(self, request, *args, **kwargs):
+ self.show_assets = request.query_params.get('show_assets', '1') == '1'
+ self.system_user_id = request.query_params.get('system_user')
+ return super().get(request, *args, **kwargs)
+
+ @staticmethod
+ def parse_node_to_tree_node(node):
+ name = '{} ({})'.format(node.value, node.assets_amount)
+ node_serializer = serializers.GrantedNodeSerializer(node)
+ data = {
+ 'id': node.key,
+ 'name': name,
+ 'title': name,
+ 'pId': node.parent_key,
+ 'isParent': True,
+ 'open': node.is_root(),
+ 'meta': {
+ 'node': node_serializer.data,
+ 'type': 'node'
+ }
+ }
+ tree_node = TreeNode(**data)
+ return tree_node
+
+ @staticmethod
+ def parse_asset_to_tree_node(node, asset, system_users):
+ system_user_serializer = serializers.GrantedSystemUserSerializer(
+ system_users, many=True
+ )
+ asset_serializer = serializers.GrantedAssetSerializer(asset)
+ icon_skin = 'file'
+ if asset.platform.lower() == 'windows':
+ icon_skin = 'windows'
+ elif asset.platform.lower() == 'linux':
+ icon_skin = 'linux'
+ data = {
+ 'id': str(asset.id),
+ 'name': asset.hostname,
+ 'title': asset.ip,
+ 'pId': node.key,
+ 'isParent': False,
+ 'open': False,
+ 'iconSkin': icon_skin,
+ 'meta': {
+ 'system_users': system_user_serializer.data,
+ 'type': 'asset',
+ 'asset': asset_serializer.data
+ }
+ }
+ tree_node = TreeNode(**data)
+ return tree_node
+
+ def get_permissions(self):
+ if self.kwargs.get('pk') is None:
+ self.permission_classes = (IsValidUser,)
+ return super().get_permissions()
+
+ def get_queryset(self):
+ self.change_org_if_need()
+ user_id = self.kwargs.get('pk', '')
+ queryset = []
+ if not user_id:
+ user = self.request.user
+ else:
+ user = get_object_or_404(User, id=user_id)
+ util = AssetPermissionUtil(user)
+ if self.system_user_id:
+ util.filter_permission_with_system_user(system_user=self.system_user_id)
+ nodes = util.get_nodes_with_assets()
+ for node, assets in nodes.items():
+ data = self.parse_node_to_tree_node(node)
+ queryset.append(data)
+ if not self.show_assets:
+ continue
+ for asset, system_users in assets.items():
+ data = self.parse_asset_to_tree_node(node, asset, system_users)
+ queryset.append(data)
+ queryset = sorted(queryset)
+ return queryset
+
+
class UserGrantedNodeAssetsApi(AssetsFilterMixin, ListAPIView):
"""
查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产
diff --git a/apps/perms/serializers.py b/apps/perms/serializers.py
index cc5d0edcd..e307a8ed4 100644
--- a/apps/perms/serializers.py
+++ b/apps/perms/serializers.py
@@ -5,9 +5,16 @@ from rest_framework import serializers
from common.fields import StringManyToManyField
from .models import AssetPermission
-from assets.models import Node
+from assets.models import Node, Asset, SystemUser
from assets.serializers import AssetGrantedSerializer
+__all__ = [
+ 'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
+ 'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
+ 'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
+ 'GrantedAssetSerializer', 'GrantedSystemUserSerializer',
+]
+
class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
@@ -74,3 +81,29 @@ class AssetPermissionNodeSerializer(serializers.ModelSerializer):
@staticmethod
def get_tree_parent(obj):
return obj.parent_key
+
+
+class GrantedNodeSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Node
+ fields = [
+ 'id', 'name', 'key', 'value',
+ ]
+
+
+class GrantedAssetSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Asset
+ fields = [
+ 'id', 'hostname', 'ip', 'port', 'protocol', 'platform',
+ 'domain', 'is_active', 'comment'
+ ]
+
+
+class GrantedSystemUserSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = SystemUser
+ fields = [
+ 'id', 'name', 'username', 'protocol', 'priority',
+ 'login_mode', 'comment'
+ ]
diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py
index adf6b45e6..8e4716fac 100644
--- a/apps/perms/urls/api_urls.py
+++ b/apps/perms/urls/api_urls.py
@@ -29,6 +29,11 @@ urlpatterns = [
api.UserGrantedNodesWithAssetsApi.as_view(), name='user-nodes-assets'),
path('user/nodes-assets/', api.UserGrantedNodesWithAssetsApi.as_view(),
name='my-nodes-assets'),
+ path('user//nodes-assets/tree/',
+ api.UserGrantedNodesWithAssetsAsTreeApi.as_view(), name='user-nodes-assets-as-tree'),
+ path('user/nodes-assets/tree/', api.UserGrantedNodesWithAssetsAsTreeApi.as_view(),
+ name='my-nodes-assets-as-tree'),
+
# 查询某个用户组授权的资产和资产组
path('user-group//assets/',
diff --git a/apps/perms/utils.py b/apps/perms/utils.py
index 8ebe696e0..8b79175aa 100644
--- a/apps/perms/utils.py
+++ b/apps/perms/utils.py
@@ -11,36 +11,41 @@ from .hands import Node
logger = get_logger(__file__)
-class Tree:
+class GenerateTree:
def __init__(self):
- self.__all_nodes = Node.objects.all().prefetch_related('assets')
+ """
+ nodes: {"node_instance": {
+ "asset_instance": set("system_user")
+ }
+ """
+ self.__all_nodes = Node.objects.all()
self.__node_asset_map = defaultdict(set)
self.nodes = defaultdict(dict)
- self.root = Node.root()
- self.init_node_asset_map()
-
- def init_node_asset_map(self):
- for node in self.__all_nodes:
- assets = [a.id for a in node.assets.all()]
- for asset in assets:
- self.__node_asset_map[str(asset)].add(node)
def add_asset(self, asset, system_users):
- nodes = self.__node_asset_map.get(str(asset.id), [])
+ nodes = asset.nodes.all()
self.add_nodes(nodes)
for node in nodes:
self.nodes[node][asset].update(system_users)
+ def get_nodes(self):
+ for node in self.nodes:
+ assets = set(self.nodes.get(node).keys())
+ for n in self.nodes.keys():
+ if n.key.startswith(node.key + ':'):
+ assets.update(set(self.nodes[n].keys()))
+ node.assets_amount = len(assets)
+ return self.nodes
+
def add_node(self, node):
if node in self.nodes:
return
else:
self.nodes[node] = defaultdict(set)
- if node.key == self.root.key:
+ if node.is_root():
return
- parent_key = ':'.join(node.key.split(':')[:-1])
for n in self.__all_nodes:
- if n.key == parent_key:
+ if n.key == node.parent_key:
self.add_node(n)
break
@@ -107,6 +112,9 @@ class AssetPermissionUtil:
self._permissions = permissions
return permissions
+ def filter_permission_with_system_user(self, system_user):
+ self._permissions = self.permissions.filter(system_users=system_user)
+
def get_nodes_direct(self):
"""
返回用户/组授权规则直接关联的节点
@@ -150,10 +158,17 @@ class AssetPermissionUtil:
:return:
"""
assets = self.get_assets()
- tree = Tree()
+ tree = GenerateTree()
for asset, system_users in assets.items():
tree.add_asset(asset, system_users)
- return tree.nodes
+ return tree.get_nodes()
+
+ def get_system_users(self):
+ system_users = set()
+ permissions = self.permissions.prefetch_related('system_users')
+ for perm in permissions:
+ system_users.update(perm.system_users.all())
+ return system_users
def is_obj_attr_has(obj, val, attrs=("hostname", "ip", "comment")):
diff --git a/apps/static/css/plugins/codemirror/ambiance.css b/apps/static/css/plugins/codemirror/ambiance.css
new file mode 100755
index 000000000..c844566ea
--- /dev/null
+++ b/apps/static/css/plugins/codemirror/ambiance.css
@@ -0,0 +1,77 @@
+/* ambiance theme for codemirror */
+
+/* Color scheme */
+
+.cm-s-ambiance .cm-keyword { color: #cda869; }
+.cm-s-ambiance .cm-atom { color: #CF7EA9; }
+.cm-s-ambiance .cm-number { color: #78CF8A; }
+.cm-s-ambiance .cm-def { color: #aac6e3; }
+.cm-s-ambiance .cm-variable { color: #ffb795; }
+.cm-s-ambiance .cm-variable-2 { color: #eed1b3; }
+.cm-s-ambiance .cm-variable-3 { color: #faded3; }
+.cm-s-ambiance .cm-property { color: #eed1b3; }
+.cm-s-ambiance .cm-operator {color: #fa8d6a;}
+.cm-s-ambiance .cm-comment { color: #555; font-style:italic; }
+.cm-s-ambiance .cm-string { color: #8f9d6a; }
+.cm-s-ambiance .cm-string-2 { color: #9d937c; }
+.cm-s-ambiance .cm-meta { color: #D2A8A1; }
+.cm-s-ambiance .cm-qualifier { color: yellow; }
+.cm-s-ambiance .cm-builtin { color: #9999cc; }
+.cm-s-ambiance .cm-bracket { color: #24C2C7; }
+.cm-s-ambiance .cm-tag { color: #fee4ff }
+.cm-s-ambiance .cm-attribute { color: #9B859D; }
+.cm-s-ambiance .cm-header {color: blue;}
+.cm-s-ambiance .cm-quote { color: #24C2C7; }
+.cm-s-ambiance .cm-hr { color: pink; }
+.cm-s-ambiance .cm-link { color: #F4C20B; }
+.cm-s-ambiance .cm-special { color: #FF9D00; }
+.cm-s-ambiance .cm-error { color: #AF2018; }
+
+.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }
+.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }
+
+.cm-s-ambiance .CodeMirror-selected {
+ background: rgba(255, 255, 255, 0.15);
+}
+.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected {
+ background: rgba(255, 255, 255, 0.10);
+}
+
+/* Editor styling */
+
+.cm-s-ambiance.CodeMirror {
+ line-height: 1.40em;
+ color: #E6E1DC;
+ background-color: #202020;
+ -webkit-box-shadow: inset 0 0 10px black;
+ -moz-box-shadow: inset 0 0 10px black;
+ box-shadow: inset 0 0 10px black;
+}
+
+.cm-s-ambiance .CodeMirror-gutters {
+ background: #3D3D3D;
+ border-right: 1px solid #4D4D4D;
+ box-shadow: 0 10px 20px black;
+}
+
+.cm-s-ambiance .CodeMirror-linenumber {
+ text-shadow: 0px 1px 1px #4d4d4d;
+ color: #111;
+ padding: 0 5px;
+}
+
+.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; }
+.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; }
+
+.cm-s-ambiance .CodeMirror-lines .CodeMirror-cursor {
+ border-left: 1px solid #7991E8;
+}
+
+.cm-s-ambiance .CodeMirror-activeline-background {
+ background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);
+}
+
+.cm-s-ambiance.CodeMirror,
+.cm-s-ambiance .CodeMirror-gutters {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC");
+}
diff --git a/apps/static/css/plugins/codemirror/codemirror.css b/apps/static/css/plugins/codemirror/codemirror.css
new file mode 100755
index 000000000..68c67b170
--- /dev/null
+++ b/apps/static/css/plugins/codemirror/codemirror.css
@@ -0,0 +1,309 @@
+/* BASICS */
+
+.CodeMirror {
+ /* Set height, width, borders, and global font properties here */
+ font-family: monospace;
+ height: 300px;
+}
+.CodeMirror-scroll {
+ /* Set scrolling behaviour here */
+ overflow: auto;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+ padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+ padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+ border-right: 1px solid #ddd;
+ background-color: #f7f7f7;
+ white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+ padding: 0 3px 0 5px;
+ min-width: 20px;
+ text-align: right;
+ color: #999;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror div.CodeMirror-cursor {
+ border-left: 1px solid black;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+ border-left: 1px solid silver;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: #7e7;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursors {
+ z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+ width: auto;
+ border: 0;
+ -webkit-animation: blink 1.06s steps(1) infinite;
+ -moz-animation: blink 1.06s steps(1) infinite;
+ animation: blink 1.06s steps(1) infinite;
+}
+@-moz-keyframes blink {
+ 0% { background: #7e7; }
+ 50% { background: none; }
+ 100% { background: #7e7; }
+}
+@-webkit-keyframes blink {
+ 0% { background: #7e7; }
+ 50% { background: none; }
+ 100% { background: #7e7; }
+}
+@keyframes blink {
+ 0% { background: #7e7; }
+ 50% { background: none; }
+ 100% { background: #7e7; }
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+div.CodeMirror-overwrite div.CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-ruler {
+ border-left: 1px solid #ccc;
+ position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+ the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+ line-height: 1;
+ position: relative;
+ overflow: hidden;
+ background: white;
+ color: black;
+}
+
+.CodeMirror-scroll {
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-right: -30px;
+ padding-bottom: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+.CodeMirror-sizer {
+ position: relative;
+ border-right: 30px solid transparent;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actuall scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ right: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; left: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; left: 0; top: 0;
+ padding-bottom: 30px;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ padding-bottom: 30px;
+ margin-bottom: -32px;
+ display: inline-block;
+ /* Hack to make IE7 behave */
+ *zoom:1;
+ *display:inline;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+}
+
+.CodeMirror-lines {
+ cursor: text;
+ min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+
+.CodeMirror-linebackground {
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ overflow: auto;
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-wrap .CodeMirror-scroll {
+ overflow-x: hidden;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%;
+ height: 0;
+ overflow: hidden;
+ visibility: hidden;
+}
+.CodeMirror-measure pre { position: static; }
+
+.CodeMirror div.CodeMirror-cursor {
+ position: absolute;
+ border-right: none;
+ width: 0;
+}
+
+div.CodeMirror-cursors {
+ visibility: hidden;
+ position: relative;
+ z-index: 3;
+}
+.CodeMirror-focused div.CodeMirror-cursors {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+
+.cm-searching {
+ background: #ffa;
+ background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursors {
+ visibility: hidden;
+ }
+}
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
diff --git a/apps/static/js/plugins/codemirror/codemirror.js b/apps/static/js/plugins/codemirror/codemirror.js
new file mode 100755
index 000000000..4f8a23bde
--- /dev/null
+++ b/apps/static/js/plugins/codemirror/codemirror.js
@@ -0,0 +1,7830 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// This is CodeMirror (http://codemirror.net), a code editor
+// implemented in JavaScript on top of the browser's DOM.
+//
+// You can find some technical background for some of the code below
+// at http://marijnhaverbeke.nl/blog/#cm-internals .
+
+(function(mod) {
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
+ module.exports = mod();
+ else if (typeof define == "function" && define.amd) // AMD
+ return define([], mod);
+ else // Plain browser env
+ this.CodeMirror = mod();
+})(function() {
+ "use strict";
+
+ // BROWSER SNIFFING
+
+ // Kludges for bugs and behavior differences that can't be feature
+ // detected are enabled based on userAgent etc sniffing.
+
+ var gecko = /gecko\/\d/i.test(navigator.userAgent);
+ // ie_uptoN means Internet Explorer version N or lower
+ var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
+ var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
+ var ie = ie_upto10 || ie_11up;
+ var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
+ var webkit = /WebKit\//.test(navigator.userAgent);
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
+ var chrome = /Chrome\//.test(navigator.userAgent);
+ var presto = /Opera\//.test(navigator.userAgent);
+ var safari = /Apple Computer/.test(navigator.vendor);
+ var khtml = /KHTML\//.test(navigator.userAgent);
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
+ var phantom = /PhantomJS/.test(navigator.userAgent);
+
+ var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+ // This is woefully incomplete. Suggestions for alternative methods welcome.
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
+ var mac = ios || /Mac/.test(navigator.platform);
+ var windows = /win/i.test(navigator.platform);
+
+ var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
+ if (presto_version) presto_version = Number(presto_version[1]);
+ if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
+ // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
+ var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
+ var captureRightClick = gecko || (ie && ie_version >= 9);
+
+ // Optimize some code when these features are not used.
+ var sawReadOnlySpans = false, sawCollapsedSpans = false;
+
+ // EDITOR CONSTRUCTOR
+
+ // A CodeMirror instance represents an editor. This is the object
+ // that user code is usually dealing with.
+
+ function CodeMirror(place, options) {
+ if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
+
+ this.options = options = options ? copyObj(options) : {};
+ // Determine effective options based on given values and defaults.
+ copyObj(defaults, options, false);
+ setGuttersForLineNumbers(options);
+
+ var doc = options.value;
+ if (typeof doc == "string") doc = new Doc(doc, options.mode);
+ this.doc = doc;
+
+ var display = this.display = new Display(place, doc);
+ display.wrapper.CodeMirror = this;
+ updateGutters(this);
+ themeChanged(this);
+ if (options.lineWrapping)
+ this.display.wrapper.className += " CodeMirror-wrap";
+ if (options.autofocus && !mobile) focusInput(this);
+
+ this.state = {
+ keyMaps: [], // stores maps added by addKeyMap
+ overlays: [], // highlighting overlays, as added by addOverlay
+ modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
+ overwrite: false, focused: false,
+ suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
+ pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput
+ draggingText: false,
+ highlight: new Delayed() // stores highlight worker timeout
+ };
+
+ // Override magic textarea content restore that IE sometimes does
+ // on our hidden textarea on reload
+ if (ie && ie_version < 11) setTimeout(bind(resetInput, this, true), 20);
+
+ registerEventHandlers(this);
+ ensureGlobalHandlers();
+
+ startOperation(this);
+ this.curOp.forceUpdate = true;
+ attachDoc(this, doc);
+
+ if ((options.autofocus && !mobile) || activeElt() == display.input)
+ setTimeout(bind(onFocus, this), 20);
+ else
+ onBlur(this);
+
+ for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
+ optionHandlers[opt](this, options[opt], Init);
+ maybeUpdateLineNumberWidth(this);
+ for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
+ endOperation(this);
+ }
+
+ // DISPLAY CONSTRUCTOR
+
+ // The display handles the DOM integration, both for input reading
+ // and content drawing. It holds references to DOM nodes and
+ // display-related state.
+
+ function Display(place, doc) {
+ var d = this;
+
+ // The semihidden textarea that is focused when the editor is
+ // focused, and receives input.
+ var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
+ // The textarea is kept positioned near the cursor to prevent the
+ // fact that it'll be scrolled into view on input from scrolling
+ // our fake cursor out of view. On webkit, when wrap=off, paste is
+ // very slow. So make the area wide instead.
+ if (webkit) input.style.width = "1000px";
+ else input.setAttribute("wrap", "off");
+ // If border: 0; -- iOS fails to open keyboard (issue #1287)
+ if (ios) input.style.border = "1px solid black";
+ input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false");
+
+ // Wraps and hides input textarea
+ d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
+ // The fake scrollbar elements.
+ d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
+ d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
+ // Covers bottom-right square when both scrollbars are present.
+ d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
+ // Covers bottom of gutter when coverGutterNextToScrollbar is on
+ // and h scrollbar is present.
+ d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
+ // Will contain the actual code, positioned to cover the viewport.
+ d.lineDiv = elt("div", null, "CodeMirror-code");
+ // Elements are added to these to represent selection and cursors.
+ d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
+ d.cursorDiv = elt("div", null, "CodeMirror-cursors");
+ // A visibility: hidden element used to find the size of things.
+ d.measure = elt("div", null, "CodeMirror-measure");
+ // When lines outside of the viewport are measured, they are drawn in this.
+ d.lineMeasure = elt("div", null, "CodeMirror-measure");
+ // Wraps everything that needs to exist inside the vertically-padded coordinate system
+ d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
+ null, "position: relative; outline: none");
+ // Moved around its parent to cover visible view.
+ d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
+ // Set to the height of the document, allowing scrolling.
+ d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
+ // Behavior of elts with overflow: auto and padding is
+ // inconsistent across browsers. This is used to ensure the
+ // scrollable area is big enough.
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
+ // Will contain the gutters, if any.
+ d.gutters = elt("div", null, "CodeMirror-gutters");
+ d.lineGutter = null;
+ // Actual scrollable element.
+ d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
+ d.scroller.setAttribute("tabIndex", "-1");
+ // The element in which the editor lives.
+ d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
+ d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
+
+ // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
+ if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
+ // Needed to hide big blue blinking cursor on Mobile Safari
+ if (ios) input.style.width = "0px";
+ if (!webkit) d.scroller.draggable = true;
+ // Needed to handle Tab key in KHTML
+ if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+ if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
+
+ if (place.appendChild) place.appendChild(d.wrapper);
+ else place(d.wrapper);
+
+ // Current rendered range (may be bigger than the view window).
+ d.viewFrom = d.viewTo = doc.first;
+ // Information about the rendered lines.
+ d.view = [];
+ // Holds info about a single rendered line when it was rendered
+ // for measurement, while not in view.
+ d.externalMeasured = null;
+ // Empty space (in pixels) above the view
+ d.viewOffset = 0;
+ d.lastSizeC = 0;
+ d.updateLineNumbers = null;
+
+ // Used to only resize the line number gutter when necessary (when
+ // the amount of lines crosses a boundary that makes its width change)
+ d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
+ // See readInput and resetInput
+ d.prevInput = "";
+ // Set to true when a non-horizontal-scrolling line widget is
+ // added. As an optimization, line widget aligning is skipped when
+ // this is false.
+ d.alignWidgets = false;
+ // Flag that indicates whether we expect input to appear real soon
+ // now (after some event like 'keypress' or 'input') and are
+ // polling intensively.
+ d.pollingFast = false;
+ // Self-resetting timeout for the poller
+ d.poll = new Delayed();
+
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+
+ // Tracks when resetInput has punted to just putting a short
+ // string into the textarea instead of the full selection.
+ d.inaccurateSelection = false;
+
+ // Tracks the maximum line length so that the horizontal scrollbar
+ // can be kept static when scrolling.
+ d.maxLine = null;
+ d.maxLineLength = 0;
+ d.maxLineChanged = false;
+
+ // Used for measuring wheel scrolling granularity
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
+
+ // True when shift is held down.
+ d.shift = false;
+
+ // Used to track whether anything happened since the context menu
+ // was opened.
+ d.selForContextMenu = null;
+ }
+
+ // STATE UPDATES
+
+ // Used to get the editor into a consistent state again when options change.
+
+ function loadMode(cm) {
+ cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
+ resetModeState(cm);
+ }
+
+ function resetModeState(cm) {
+ cm.doc.iter(function(line) {
+ if (line.stateAfter) line.stateAfter = null;
+ if (line.styles) line.styles = null;
+ });
+ cm.doc.frontier = cm.doc.first;
+ startWorker(cm, 100);
+ cm.state.modeGen++;
+ if (cm.curOp) regChange(cm);
+ }
+
+ function wrappingChanged(cm) {
+ if (cm.options.lineWrapping) {
+ addClass(cm.display.wrapper, "CodeMirror-wrap");
+ cm.display.sizer.style.minWidth = "";
+ } else {
+ rmClass(cm.display.wrapper, "CodeMirror-wrap");
+ findMaxLine(cm);
+ }
+ estimateLineHeights(cm);
+ regChange(cm);
+ clearCaches(cm);
+ setTimeout(function(){updateScrollbars(cm);}, 100);
+ }
+
+ // Returns a function that estimates the height of a line, to use as
+ // first approximation until the line becomes visible (and is thus
+ // properly measurable).
+ function estimateHeight(cm) {
+ var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
+ var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
+ return function(line) {
+ if (lineIsHidden(cm.doc, line)) return 0;
+
+ var widgetsHeight = 0;
+ if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
+ if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
+ }
+
+ if (wrapping)
+ return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
+ else
+ return widgetsHeight + th;
+ };
+ }
+
+ function estimateLineHeights(cm) {
+ var doc = cm.doc, est = estimateHeight(cm);
+ doc.iter(function(line) {
+ var estHeight = est(line);
+ if (estHeight != line.height) updateLineHeight(line, estHeight);
+ });
+ }
+
+ function keyMapChanged(cm) {
+ var map = keyMap[cm.options.keyMap], style = map.style;
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
+ (style ? " cm-keymap-" + style : "");
+ }
+
+ function themeChanged(cm) {
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
+ cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
+ clearCaches(cm);
+ }
+
+ function guttersChanged(cm) {
+ updateGutters(cm);
+ regChange(cm);
+ setTimeout(function(){alignHorizontally(cm);}, 20);
+ }
+
+ // Rebuild the gutter elements, ensure the margin to the left of the
+ // code matches their width.
+ function updateGutters(cm) {
+ var gutters = cm.display.gutters, specs = cm.options.gutters;
+ removeChildren(gutters);
+ for (var i = 0; i < specs.length; ++i) {
+ var gutterClass = specs[i];
+ var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
+ if (gutterClass == "CodeMirror-linenumbers") {
+ cm.display.lineGutter = gElt;
+ gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
+ }
+ }
+ gutters.style.display = i ? "" : "none";
+ updateGutterSpace(cm);
+ }
+
+ function updateGutterSpace(cm) {
+ var width = cm.display.gutters.offsetWidth;
+ cm.display.sizer.style.marginLeft = width + "px";
+ cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
+ }
+
+ // Compute the character length of a line, taking into account
+ // collapsed ranges (see markText) that might hide parts, and join
+ // other lines onto it.
+ function lineLength(line) {
+ if (line.height == 0) return 0;
+ var len = line.text.length, merged, cur = line;
+ while (merged = collapsedSpanAtStart(cur)) {
+ var found = merged.find(0, true);
+ cur = found.from.line;
+ len += found.from.ch - found.to.ch;
+ }
+ cur = line;
+ while (merged = collapsedSpanAtEnd(cur)) {
+ var found = merged.find(0, true);
+ len -= cur.text.length - found.from.ch;
+ cur = found.to.line;
+ len += cur.text.length - found.to.ch;
+ }
+ return len;
+ }
+
+ // Find the longest line in the document.
+ function findMaxLine(cm) {
+ var d = cm.display, doc = cm.doc;
+ d.maxLine = getLine(doc, doc.first);
+ d.maxLineLength = lineLength(d.maxLine);
+ d.maxLineChanged = true;
+ doc.iter(function(line) {
+ var len = lineLength(line);
+ if (len > d.maxLineLength) {
+ d.maxLineLength = len;
+ d.maxLine = line;
+ }
+ });
+ }
+
+ // Make sure the gutters options contains the element
+ // "CodeMirror-linenumbers" when the lineNumbers option is true.
+ function setGuttersForLineNumbers(options) {
+ var found = indexOf(options.gutters, "CodeMirror-linenumbers");
+ if (found == -1 && options.lineNumbers) {
+ options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
+ } else if (found > -1 && !options.lineNumbers) {
+ options.gutters = options.gutters.slice(0);
+ options.gutters.splice(found, 1);
+ }
+ }
+
+ // SCROLLBARS
+
+ function hScrollbarTakesSpace(cm) {
+ return cm.display.scroller.clientHeight - cm.display.wrapper.clientHeight < scrollerCutOff - 3;
+ }
+
+ // Prepare DOM reads needed to update the scrollbars. Done in one
+ // shot to minimize update/measure roundtrips.
+ function measureForScrollbars(cm) {
+ var scroll = cm.display.scroller;
+ return {
+ clientHeight: scroll.clientHeight,
+ barHeight: cm.display.scrollbarV.clientHeight,
+ scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
+ hScrollbarTakesSpace: hScrollbarTakesSpace(cm),
+ barWidth: cm.display.scrollbarH.clientWidth,
+ docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
+ };
+ }
+
+ // Re-synchronize the fake scrollbars with the actual size of the
+ // content.
+ function updateScrollbars(cm, measure) {
+ if (!measure) measure = measureForScrollbars(cm);
+ var d = cm.display, sWidth = scrollbarWidth(d.measure);
+ var scrollHeight = measure.docHeight + scrollerCutOff;
+ var needsH = measure.scrollWidth > measure.clientWidth;
+ if (needsH && measure.scrollWidth <= measure.clientWidth + 1 &&
+ sWidth > 0 && !measure.hScrollbarTakesSpace)
+ needsH = false; // (Issue #2562)
+ var needsV = scrollHeight > measure.clientHeight;
+
+ if (needsV) {
+ d.scrollbarV.style.display = "block";
+ d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0";
+ // A bug in IE8 can cause this value to be negative, so guard it.
+ d.scrollbarV.firstChild.style.height =
+ Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
+ } else {
+ d.scrollbarV.style.display = "";
+ d.scrollbarV.firstChild.style.height = "0";
+ }
+ if (needsH) {
+ d.scrollbarH.style.display = "block";
+ d.scrollbarH.style.right = needsV ? sWidth + "px" : "0";
+ d.scrollbarH.firstChild.style.width =
+ (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px";
+ } else {
+ d.scrollbarH.style.display = "";
+ d.scrollbarH.firstChild.style.width = "0";
+ }
+ if (needsH && needsV) {
+ d.scrollbarFiller.style.display = "block";
+ d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = sWidth + "px";
+ } else d.scrollbarFiller.style.display = "";
+ if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
+ d.gutterFiller.style.display = "block";
+ d.gutterFiller.style.height = sWidth + "px";
+ d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
+ } else d.gutterFiller.style.display = "";
+
+ if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
+ if (sWidth === 0) {
+ var w = mac && !mac_geMountainLion ? "12px" : "18px";
+ d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
+ var barMouseDown = function(e) {
+ if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
+ operation(cm, onMouseDown)(e);
+ };
+ on(d.scrollbarV, "mousedown", barMouseDown);
+ on(d.scrollbarH, "mousedown", barMouseDown);
+ }
+ cm.state.checkedOverlayScrollbar = true;
+ }
+ }
+
+ // Compute the lines that are visible in a given viewport (defaults
+ // the the current scroll position). viewport may contain top,
+ // height, and ensure (see op.scrollToPos) properties.
+ function visibleLines(display, doc, viewport) {
+ var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
+ top = Math.floor(top - paddingTop(display));
+ var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
+
+ var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
+ // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
+ // forces those lines into the viewport (if possible).
+ if (viewport && viewport.ensure) {
+ var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
+ if (ensureFrom < from)
+ return {from: ensureFrom,
+ to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
+ if (Math.min(ensureTo, doc.lastLine()) >= to)
+ return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
+ to: ensureTo};
+ }
+ return {from: from, to: Math.max(to, from + 1)};
+ }
+
+ // LINE NUMBERS
+
+ // Re-align line numbers and gutter marks to compensate for
+ // horizontal scrolling.
+ function alignHorizontally(cm) {
+ var display = cm.display, view = display.view;
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
+ var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
+ var gutterW = display.gutters.offsetWidth, left = comp + "px";
+ for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
+ if (cm.options.fixedGutter && view[i].gutter)
+ view[i].gutter.style.left = left;
+ var align = view[i].alignable;
+ if (align) for (var j = 0; j < align.length; j++)
+ align[j].style.left = left;
+ }
+ if (cm.options.fixedGutter)
+ display.gutters.style.left = (comp + gutterW) + "px";
+ }
+
+ // Used to ensure that the line number gutter is still the right
+ // size for the current document size. Returns true when an update
+ // is needed.
+ function maybeUpdateLineNumberWidth(cm) {
+ if (!cm.options.lineNumbers) return false;
+ var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
+ if (last.length != display.lineNumChars) {
+ var test = display.measure.appendChild(elt("div", [elt("div", last)],
+ "CodeMirror-linenumber CodeMirror-gutter-elt"));
+ var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
+ display.lineGutter.style.width = "";
+ display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
+ display.lineNumWidth = display.lineNumInnerWidth + padding;
+ display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
+ display.lineGutter.style.width = display.lineNumWidth + "px";
+ updateGutterSpace(cm);
+ return true;
+ }
+ return false;
+ }
+
+ function lineNumberFor(options, i) {
+ return String(options.lineNumberFormatter(i + options.firstLineNumber));
+ }
+
+ // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
+ // but using getBoundingClientRect to get a sub-pixel-accurate
+ // result.
+ function compensateForHScroll(display) {
+ return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
+ }
+
+ // DISPLAY DRAWING
+
+ function DisplayUpdate(cm, viewport, force) {
+ var display = cm.display;
+
+ this.viewport = viewport;
+ // Store some values that we'll need later (but don't want to force a relayout for)
+ this.visible = visibleLines(display, cm.doc, viewport);
+ this.editorIsHidden = !display.wrapper.offsetWidth;
+ this.wrapperHeight = display.wrapper.clientHeight;
+ this.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo;
+ this.oldScrollerWidth = display.scroller.clientWidth;
+ this.force = force;
+ this.dims = getDimensions(cm);
+ }
+
+ // Does the actual updating of the line display. Bails out
+ // (returning false) when there is nothing to be done and forced is
+ // false.
+ function updateDisplayIfNeeded(cm, update) {
+ var display = cm.display, doc = cm.doc;
+ if (update.editorIsHidden) {
+ resetView(cm);
+ return false;
+ }
+
+ // Bail out if the visible area is already rendered and nothing changed.
+ if (!update.force &&
+ update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
+ countDirtyView(cm) == 0)
+ return false;
+
+ if (maybeUpdateLineNumberWidth(cm)) {
+ resetView(cm);
+ update.dims = getDimensions(cm);
+ }
+
+ // Compute a suitable new viewport (from & to)
+ var end = doc.first + doc.size;
+ var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
+ var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
+ if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
+ if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
+ if (sawCollapsedSpans) {
+ from = visualLineNo(cm.doc, from);
+ to = visualLineEndNo(cm.doc, to);
+ }
+
+ var different = from != display.viewFrom || to != display.viewTo ||
+ display.lastSizeC != update.wrapperHeight;
+ adjustView(cm, from, to);
+
+ display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
+ // Position the mover div to align with the current scroll position
+ cm.display.mover.style.top = display.viewOffset + "px";
+
+ var toUpdate = countDirtyView(cm);
+ if (!different && toUpdate == 0 && !update.force &&
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
+ return false;
+
+ // For big changes, we hide the enclosing element during the
+ // update, since that speeds up the operations on most browsers.
+ var focused = activeElt();
+ if (toUpdate > 4) display.lineDiv.style.display = "none";
+ patchDisplay(cm, display.updateLineNumbers, update.dims);
+ if (toUpdate > 4) display.lineDiv.style.display = "";
+ // There might have been a widget with a focused element that got
+ // hidden or updated, if so re-focus it.
+ if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
+
+ // Prevent selection and cursors from interfering with the scroll
+ // width.
+ removeChildren(display.cursorDiv);
+ removeChildren(display.selectionDiv);
+
+ if (different) {
+ display.lastSizeC = update.wrapperHeight;
+ startWorker(cm, 400);
+ }
+
+ display.updateLineNumbers = null;
+
+ return true;
+ }
+
+ function postUpdateDisplay(cm, update) {
+ var force = update.force, viewport = update.viewport;
+ for (var first = true;; first = false) {
+ if (first && cm.options.lineWrapping && update.oldScrollerWidth != cm.display.scroller.clientWidth) {
+ force = true;
+ } else {
+ force = false;
+ // Clip forced viewport to actual scrollable area.
+ if (viewport && viewport.top != null)
+ viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - scrollerCutOff -
+ cm.display.scroller.clientHeight, viewport.top)};
+ // Updated line heights might result in the drawn area not
+ // actually covering the viewport. Keep looping until it does.
+ update.visible = visibleLines(cm.display, cm.doc, viewport);
+ if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
+ break;
+ }
+ if (!updateDisplayIfNeeded(cm, update)) break;
+ updateHeightsInViewport(cm);
+ var barMeasure = measureForScrollbars(cm);
+ updateSelection(cm);
+ setDocumentHeight(cm, barMeasure);
+ updateScrollbars(cm, barMeasure);
+ }
+
+ signalLater(cm, "update", cm);
+ if (cm.display.viewFrom != update.oldViewFrom || cm.display.viewTo != update.oldViewTo)
+ signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
+ }
+
+ function updateDisplaySimple(cm, viewport) {
+ var update = new DisplayUpdate(cm, viewport);
+ if (updateDisplayIfNeeded(cm, update)) {
+ updateHeightsInViewport(cm);
+ postUpdateDisplay(cm, update);
+ var barMeasure = measureForScrollbars(cm);
+ updateSelection(cm);
+ setDocumentHeight(cm, barMeasure);
+ updateScrollbars(cm, barMeasure);
+ }
+ }
+
+ function setDocumentHeight(cm, measure) {
+ cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
+ cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
+ }
+
+ function checkForWebkitWidthBug(cm, measure) {
+ // Work around Webkit bug where it sometimes reserves space for a
+ // non-existing phantom scrollbar in the scroller (Issue #2420)
+ if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
+ cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
+ cm.display.gutters.style.height = measure.docHeight + "px";
+ }
+ }
+
+ // Read the actual heights of the rendered lines, and update their
+ // stored heights to match.
+ function updateHeightsInViewport(cm) {
+ var display = cm.display;
+ var prevBottom = display.lineDiv.offsetTop;
+ for (var i = 0; i < display.view.length; i++) {
+ var cur = display.view[i], height;
+ if (cur.hidden) continue;
+ if (ie && ie_version < 8) {
+ var bot = cur.node.offsetTop + cur.node.offsetHeight;
+ height = bot - prevBottom;
+ prevBottom = bot;
+ } else {
+ var box = cur.node.getBoundingClientRect();
+ height = box.bottom - box.top;
+ }
+ var diff = cur.line.height - height;
+ if (height < 2) height = textHeight(display);
+ if (diff > .001 || diff < -.001) {
+ updateLineHeight(cur.line, height);
+ updateWidgetHeight(cur.line);
+ if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
+ updateWidgetHeight(cur.rest[j]);
+ }
+ }
+ }
+
+ // Read and store the height of line widgets associated with the
+ // given line.
+ function updateWidgetHeight(line) {
+ if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
+ line.widgets[i].height = line.widgets[i].node.offsetHeight;
+ }
+
+ // Do a bulk-read of the DOM positions and sizes needed to draw the
+ // view, so that we don't interleave reading and writing to the DOM.
+ function getDimensions(cm) {
+ var d = cm.display, left = {}, width = {};
+ var gutterLeft = d.gutters.clientLeft;
+ for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
+ left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
+ width[cm.options.gutters[i]] = n.clientWidth;
+ }
+ return {fixedPos: compensateForHScroll(d),
+ gutterTotalWidth: d.gutters.offsetWidth,
+ gutterLeft: left,
+ gutterWidth: width,
+ wrapperWidth: d.wrapper.clientWidth};
+ }
+
+ // Sync the actual display DOM structure with display.view, removing
+ // nodes for lines that are no longer in view, and creating the ones
+ // that are not there yet, and updating the ones that are out of
+ // date.
+ function patchDisplay(cm, updateNumbersFrom, dims) {
+ var display = cm.display, lineNumbers = cm.options.lineNumbers;
+ var container = display.lineDiv, cur = container.firstChild;
+
+ function rm(node) {
+ var next = node.nextSibling;
+ // Works around a throw-scroll bug in OS X Webkit
+ if (webkit && mac && cm.display.currentWheelTarget == node)
+ node.style.display = "none";
+ else
+ node.parentNode.removeChild(node);
+ return next;
+ }
+
+ var view = display.view, lineN = display.viewFrom;
+ // Loop over the elements in the view, syncing cur (the DOM nodes
+ // in display.lineDiv) with the view as we go.
+ for (var i = 0; i < view.length; i++) {
+ var lineView = view[i];
+ if (lineView.hidden) {
+ } else if (!lineView.node) { // Not drawn yet
+ var node = buildLineElement(cm, lineView, lineN, dims);
+ container.insertBefore(node, cur);
+ } else { // Already drawn
+ while (cur != lineView.node) cur = rm(cur);
+ var updateNumber = lineNumbers && updateNumbersFrom != null &&
+ updateNumbersFrom <= lineN && lineView.lineNumber;
+ if (lineView.changes) {
+ if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
+ updateLineForChanges(cm, lineView, lineN, dims);
+ }
+ if (updateNumber) {
+ removeChildren(lineView.lineNumber);
+ lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
+ }
+ cur = lineView.node.nextSibling;
+ }
+ lineN += lineView.size;
+ }
+ while (cur) cur = rm(cur);
+ }
+
+ // When an aspect of a line changes, a string is added to
+ // lineView.changes. This updates the relevant part of the line's
+ // DOM structure.
+ function updateLineForChanges(cm, lineView, lineN, dims) {
+ for (var j = 0; j < lineView.changes.length; j++) {
+ var type = lineView.changes[j];
+ if (type == "text") updateLineText(cm, lineView);
+ else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
+ else if (type == "class") updateLineClasses(lineView);
+ else if (type == "widget") updateLineWidgets(lineView, dims);
+ }
+ lineView.changes = null;
+ }
+
+ // Lines with gutter elements, widgets or a background class need to
+ // be wrapped, and have the extra elements added to the wrapper div
+ function ensureLineWrapped(lineView) {
+ if (lineView.node == lineView.text) {
+ lineView.node = elt("div", null, null, "position: relative");
+ if (lineView.text.parentNode)
+ lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
+ lineView.node.appendChild(lineView.text);
+ if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
+ }
+ return lineView.node;
+ }
+
+ function updateLineBackground(lineView) {
+ var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
+ if (cls) cls += " CodeMirror-linebackground";
+ if (lineView.background) {
+ if (cls) lineView.background.className = cls;
+ else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
+ } else if (cls) {
+ var wrap = ensureLineWrapped(lineView);
+ lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
+ }
+ }
+
+ // Wrapper around buildLineContent which will reuse the structure
+ // in display.externalMeasured when possible.
+ function getLineContent(cm, lineView) {
+ var ext = cm.display.externalMeasured;
+ if (ext && ext.line == lineView.line) {
+ cm.display.externalMeasured = null;
+ lineView.measure = ext.measure;
+ return ext.built;
+ }
+ return buildLineContent(cm, lineView);
+ }
+
+ // Redraw the line's text. Interacts with the background and text
+ // classes because the mode may output tokens that influence these
+ // classes.
+ function updateLineText(cm, lineView) {
+ var cls = lineView.text.className;
+ var built = getLineContent(cm, lineView);
+ if (lineView.text == lineView.node) lineView.node = built.pre;
+ lineView.text.parentNode.replaceChild(built.pre, lineView.text);
+ lineView.text = built.pre;
+ if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
+ lineView.bgClass = built.bgClass;
+ lineView.textClass = built.textClass;
+ updateLineClasses(lineView);
+ } else if (cls) {
+ lineView.text.className = cls;
+ }
+ }
+
+ function updateLineClasses(lineView) {
+ updateLineBackground(lineView);
+ if (lineView.line.wrapClass)
+ ensureLineWrapped(lineView).className = lineView.line.wrapClass;
+ else if (lineView.node != lineView.text)
+ lineView.node.className = "";
+ var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
+ lineView.text.className = textClass || "";
+ }
+
+ function updateLineGutter(cm, lineView, lineN, dims) {
+ if (lineView.gutter) {
+ lineView.node.removeChild(lineView.gutter);
+ lineView.gutter = null;
+ }
+ var markers = lineView.line.gutterMarkers;
+ if (cm.options.lineNumbers || markers) {
+ var wrap = ensureLineWrapped(lineView);
+ var gutterWrap = lineView.gutter =
+ wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
+ (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
+ lineView.text);
+ if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
+ lineView.lineNumber = gutterWrap.appendChild(
+ elt("div", lineNumberFor(cm.options, lineN),
+ "CodeMirror-linenumber CodeMirror-gutter-elt",
+ "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
+ + cm.display.lineNumInnerWidth + "px"));
+ if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
+ var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
+ if (found)
+ gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
+ dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
+ }
+ }
+ }
+
+ function updateLineWidgets(lineView, dims) {
+ if (lineView.alignable) lineView.alignable = null;
+ for (var node = lineView.node.firstChild, next; node; node = next) {
+ var next = node.nextSibling;
+ if (node.className == "CodeMirror-linewidget")
+ lineView.node.removeChild(node);
+ }
+ insertLineWidgets(lineView, dims);
+ }
+
+ // Build a line's DOM representation from scratch
+ function buildLineElement(cm, lineView, lineN, dims) {
+ var built = getLineContent(cm, lineView);
+ lineView.text = lineView.node = built.pre;
+ if (built.bgClass) lineView.bgClass = built.bgClass;
+ if (built.textClass) lineView.textClass = built.textClass;
+
+ updateLineClasses(lineView);
+ updateLineGutter(cm, lineView, lineN, dims);
+ insertLineWidgets(lineView, dims);
+ return lineView.node;
+ }
+
+ // A lineView may contain multiple logical lines (when merged by
+ // collapsed spans). The widgets for all of them need to be drawn.
+ function insertLineWidgets(lineView, dims) {
+ insertLineWidgetsFor(lineView.line, lineView, dims, true);
+ if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
+ insertLineWidgetsFor(lineView.rest[i], lineView, dims, false);
+ }
+
+ function insertLineWidgetsFor(line, lineView, dims, allowAbove) {
+ if (!line.widgets) return;
+ var wrap = ensureLineWrapped(lineView);
+ for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
+ var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
+ if (!widget.handleMouseEvents) node.ignoreEvents = true;
+ positionLineWidget(widget, node, lineView, dims);
+ if (allowAbove && widget.above)
+ wrap.insertBefore(node, lineView.gutter || lineView.text);
+ else
+ wrap.appendChild(node);
+ signalLater(widget, "redraw");
+ }
+ }
+
+ function positionLineWidget(widget, node, lineView, dims) {
+ if (widget.noHScroll) {
+ (lineView.alignable || (lineView.alignable = [])).push(node);
+ var width = dims.wrapperWidth;
+ node.style.left = dims.fixedPos + "px";
+ if (!widget.coverGutter) {
+ width -= dims.gutterTotalWidth;
+ node.style.paddingLeft = dims.gutterTotalWidth + "px";
+ }
+ node.style.width = width + "px";
+ }
+ if (widget.coverGutter) {
+ node.style.zIndex = 5;
+ node.style.position = "relative";
+ if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
+ }
+ }
+
+ // POSITION OBJECT
+
+ // A Pos instance represents a position within the text.
+ var Pos = CodeMirror.Pos = function(line, ch) {
+ if (!(this instanceof Pos)) return new Pos(line, ch);
+ this.line = line; this.ch = ch;
+ };
+
+ // Compare two positions, return 0 if they are the same, a negative
+ // number when a is less, and a positive number otherwise.
+ var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
+
+ function copyPos(x) {return Pos(x.line, x.ch);}
+ function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
+ function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
+
+ // SELECTION / CURSOR
+
+ // Selection objects are immutable. A new one is created every time
+ // the selection changes. A selection is one or more non-overlapping
+ // (and non-touching) ranges, sorted, and an integer that indicates
+ // which one is the primary selection (the one that's scrolled into
+ // view, that getCursor returns, etc).
+ function Selection(ranges, primIndex) {
+ this.ranges = ranges;
+ this.primIndex = primIndex;
+ }
+
+ Selection.prototype = {
+ primary: function() { return this.ranges[this.primIndex]; },
+ equals: function(other) {
+ if (other == this) return true;
+ if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
+ for (var i = 0; i < this.ranges.length; i++) {
+ var here = this.ranges[i], there = other.ranges[i];
+ if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
+ }
+ return true;
+ },
+ deepCopy: function() {
+ for (var out = [], i = 0; i < this.ranges.length; i++)
+ out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
+ return new Selection(out, this.primIndex);
+ },
+ somethingSelected: function() {
+ for (var i = 0; i < this.ranges.length; i++)
+ if (!this.ranges[i].empty()) return true;
+ return false;
+ },
+ contains: function(pos, end) {
+ if (!end) end = pos;
+ for (var i = 0; i < this.ranges.length; i++) {
+ var range = this.ranges[i];
+ if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
+ return i;
+ }
+ return -1;
+ }
+ };
+
+ function Range(anchor, head) {
+ this.anchor = anchor; this.head = head;
+ }
+
+ Range.prototype = {
+ from: function() { return minPos(this.anchor, this.head); },
+ to: function() { return maxPos(this.anchor, this.head); },
+ empty: function() {
+ return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
+ }
+ };
+
+ // Take an unsorted, potentially overlapping set of ranges, and
+ // build a selection out of it. 'Consumes' ranges array (modifying
+ // it).
+ function normalizeSelection(ranges, primIndex) {
+ var prim = ranges[primIndex];
+ ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
+ primIndex = indexOf(ranges, prim);
+ for (var i = 1; i < ranges.length; i++) {
+ var cur = ranges[i], prev = ranges[i - 1];
+ if (cmp(prev.to(), cur.from()) >= 0) {
+ var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
+ var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
+ if (i <= primIndex) --primIndex;
+ ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
+ }
+ }
+ return new Selection(ranges, primIndex);
+ }
+
+ function simpleSelection(anchor, head) {
+ return new Selection([new Range(anchor, head || anchor)], 0);
+ }
+
+ // Most of the external API clips given positions to make sure they
+ // actually exist within the document.
+ function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
+ function clipPos(doc, pos) {
+ if (pos.line < doc.first) return Pos(doc.first, 0);
+ var last = doc.first + doc.size - 1;
+ if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
+ return clipToLen(pos, getLine(doc, pos.line).text.length);
+ }
+ function clipToLen(pos, linelen) {
+ var ch = pos.ch;
+ if (ch == null || ch > linelen) return Pos(pos.line, linelen);
+ else if (ch < 0) return Pos(pos.line, 0);
+ else return pos;
+ }
+ function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
+ function clipPosArray(doc, array) {
+ for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
+ return out;
+ }
+
+ // SELECTION UPDATES
+
+ // The 'scroll' parameter given to many of these indicated whether
+ // the new cursor position should be scrolled into view after
+ // modifying the selection.
+
+ // If shift is held or the extend flag is set, extends a range to
+ // include a given position (and optionally a second position).
+ // Otherwise, simply returns the range between the given positions.
+ // Used for cursor motion and such.
+ function extendRange(doc, range, head, other) {
+ if (doc.cm && doc.cm.display.shift || doc.extend) {
+ var anchor = range.anchor;
+ if (other) {
+ var posBefore = cmp(head, anchor) < 0;
+ if (posBefore != (cmp(other, anchor) < 0)) {
+ anchor = head;
+ head = other;
+ } else if (posBefore != (cmp(head, other) < 0)) {
+ head = other;
+ }
+ }
+ return new Range(anchor, head);
+ } else {
+ return new Range(other || head, head);
+ }
+ }
+
+ // Extend the primary selection range, discard the rest.
+ function extendSelection(doc, head, other, options) {
+ setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
+ }
+
+ // Extend all selections (pos is an array of selections with length
+ // equal the number of selections)
+ function extendSelections(doc, heads, options) {
+ for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
+ out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
+ var newSel = normalizeSelection(out, doc.sel.primIndex);
+ setSelection(doc, newSel, options);
+ }
+
+ // Updates a single range in the selection.
+ function replaceOneSelection(doc, i, range, options) {
+ var ranges = doc.sel.ranges.slice(0);
+ ranges[i] = range;
+ setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
+ }
+
+ // Reset the selection to a single range.
+ function setSimpleSelection(doc, anchor, head, options) {
+ setSelection(doc, simpleSelection(anchor, head), options);
+ }
+
+ // Give beforeSelectionChange handlers a change to influence a
+ // selection update.
+ function filterSelectionChange(doc, sel) {
+ var obj = {
+ ranges: sel.ranges,
+ update: function(ranges) {
+ this.ranges = [];
+ for (var i = 0; i < ranges.length; i++)
+ this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
+ clipPos(doc, ranges[i].head));
+ }
+ };
+ signal(doc, "beforeSelectionChange", doc, obj);
+ if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
+ if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
+ else return sel;
+ }
+
+ function setSelectionReplaceHistory(doc, sel, options) {
+ var done = doc.history.done, last = lst(done);
+ if (last && last.ranges) {
+ done[done.length - 1] = sel;
+ setSelectionNoUndo(doc, sel, options);
+ } else {
+ setSelection(doc, sel, options);
+ }
+ }
+
+ // Set a new selection.
+ function setSelection(doc, sel, options) {
+ setSelectionNoUndo(doc, sel, options);
+ addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
+ }
+
+ function setSelectionNoUndo(doc, sel, options) {
+ if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
+ sel = filterSelectionChange(doc, sel);
+
+ var bias = options && options.bias ||
+ (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
+ setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
+
+ if (!(options && options.scroll === false) && doc.cm)
+ ensureCursorVisible(doc.cm);
+ }
+
+ function setSelectionInner(doc, sel) {
+ if (sel.equals(doc.sel)) return;
+
+ doc.sel = sel;
+
+ if (doc.cm) {
+ doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
+ signalCursorActivity(doc.cm);
+ }
+ signalLater(doc, "cursorActivity", doc);
+ }
+
+ // Verify that the selection does not partially select any atomic
+ // marked ranges.
+ function reCheckSelection(doc) {
+ setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
+ }
+
+ // Return a selection that does not partially select any atomic
+ // ranges.
+ function skipAtomicInSelection(doc, sel, bias, mayClear) {
+ var out;
+ for (var i = 0; i < sel.ranges.length; i++) {
+ var range = sel.ranges[i];
+ var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
+ var newHead = skipAtomic(doc, range.head, bias, mayClear);
+ if (out || newAnchor != range.anchor || newHead != range.head) {
+ if (!out) out = sel.ranges.slice(0, i);
+ out[i] = new Range(newAnchor, newHead);
+ }
+ }
+ return out ? normalizeSelection(out, sel.primIndex) : sel;
+ }
+
+ // Ensure a given position is not inside an atomic range.
+ function skipAtomic(doc, pos, bias, mayClear) {
+ var flipped = false, curPos = pos;
+ var dir = bias || 1;
+ doc.cantEdit = false;
+ search: for (;;) {
+ var line = getLine(doc, curPos.line);
+ if (line.markedSpans) {
+ for (var i = 0; i < line.markedSpans.length; ++i) {
+ var sp = line.markedSpans[i], m = sp.marker;
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
+ (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
+ if (mayClear) {
+ signal(m, "beforeCursorEnter");
+ if (m.explicitlyCleared) {
+ if (!line.markedSpans) break;
+ else {--i; continue;}
+ }
+ }
+ if (!m.atomic) continue;
+ var newPos = m.find(dir < 0 ? -1 : 1);
+ if (cmp(newPos, curPos) == 0) {
+ newPos.ch += dir;
+ if (newPos.ch < 0) {
+ if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
+ else newPos = null;
+ } else if (newPos.ch > line.text.length) {
+ if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
+ else newPos = null;
+ }
+ if (!newPos) {
+ if (flipped) {
+ // Driven in a corner -- no valid cursor position found at all
+ // -- try again *with* clearing, if we didn't already
+ if (!mayClear) return skipAtomic(doc, pos, bias, true);
+ // Otherwise, turn off editing until further notice, and return the start of the doc
+ doc.cantEdit = true;
+ return Pos(doc.first, 0);
+ }
+ flipped = true; newPos = pos; dir = -dir;
+ }
+ }
+ curPos = newPos;
+ continue search;
+ }
+ }
+ }
+ return curPos;
+ }
+ }
+
+ // SELECTION DRAWING
+
+ // Redraw the selection and/or cursor
+ function drawSelection(cm) {
+ var display = cm.display, doc = cm.doc, result = {};
+ var curFragment = result.cursors = document.createDocumentFragment();
+ var selFragment = result.selection = document.createDocumentFragment();
+
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ var range = doc.sel.ranges[i];
+ var collapsed = range.empty();
+ if (collapsed || cm.options.showCursorWhenSelecting)
+ drawSelectionCursor(cm, range, curFragment);
+ if (!collapsed)
+ drawSelectionRange(cm, range, selFragment);
+ }
+
+ // Move the hidden textarea near the cursor to prevent scrolling artifacts
+ if (cm.options.moveInputWithCursor) {
+ var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
+ var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
+ result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
+ headPos.top + lineOff.top - wrapOff.top));
+ result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
+ headPos.left + lineOff.left - wrapOff.left));
+ }
+
+ return result;
+ }
+
+ function showSelection(cm, drawn) {
+ removeChildrenAndAdd(cm.display.cursorDiv, drawn.cursors);
+ removeChildrenAndAdd(cm.display.selectionDiv, drawn.selection);
+ if (drawn.teTop != null) {
+ cm.display.inputDiv.style.top = drawn.teTop + "px";
+ cm.display.inputDiv.style.left = drawn.teLeft + "px";
+ }
+ }
+
+ function updateSelection(cm) {
+ showSelection(cm, drawSelection(cm));
+ }
+
+ // Draws a cursor for the given range
+ function drawSelectionCursor(cm, range, output) {
+ var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
+
+ var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
+ cursor.style.left = pos.left + "px";
+ cursor.style.top = pos.top + "px";
+ cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
+
+ if (pos.other) {
+ // Secondary cursor, shown when on a 'jump' in bi-directional text
+ var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
+ otherCursor.style.display = "";
+ otherCursor.style.left = pos.other.left + "px";
+ otherCursor.style.top = pos.other.top + "px";
+ otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
+ }
+ }
+
+ // Draws the given range as a highlighted selection
+ function drawSelectionRange(cm, range, output) {
+ var display = cm.display, doc = cm.doc;
+ var fragment = document.createDocumentFragment();
+ var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
+
+ function add(left, top, width, bottom) {
+ if (top < 0) top = 0;
+ top = Math.round(top);
+ bottom = Math.round(bottom);
+ fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
+ "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
+ "px; height: " + (bottom - top) + "px"));
+ }
+
+ function drawForLine(line, fromArg, toArg) {
+ var lineObj = getLine(doc, line);
+ var lineLen = lineObj.text.length;
+ var start, end;
+ function coords(ch, bias) {
+ return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
+ }
+
+ iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
+ var leftPos = coords(from, "left"), rightPos, left, right;
+ if (from == to) {
+ rightPos = leftPos;
+ left = right = leftPos.left;
+ } else {
+ rightPos = coords(to - 1, "right");
+ if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
+ left = leftPos.left;
+ right = rightPos.right;
+ }
+ if (fromArg == null && from == 0) left = leftSide;
+ if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
+ add(left, leftPos.top, null, leftPos.bottom);
+ left = leftSide;
+ if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
+ }
+ if (toArg == null && to == lineLen) right = rightSide;
+ if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
+ start = leftPos;
+ if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
+ end = rightPos;
+ if (left < leftSide + 1) left = leftSide;
+ add(left, rightPos.top, right - left, rightPos.bottom);
+ });
+ return {start: start, end: end};
+ }
+
+ var sFrom = range.from(), sTo = range.to();
+ if (sFrom.line == sTo.line) {
+ drawForLine(sFrom.line, sFrom.ch, sTo.ch);
+ } else {
+ var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
+ var singleVLine = visualLine(fromLine) == visualLine(toLine);
+ var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
+ var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
+ if (singleVLine) {
+ if (leftEnd.top < rightStart.top - 2) {
+ add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
+ add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
+ } else {
+ add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
+ }
+ }
+ if (leftEnd.bottom < rightStart.top)
+ add(leftSide, leftEnd.bottom, null, rightStart.top);
+ }
+
+ output.appendChild(fragment);
+ }
+
+ // Cursor-blinking
+ function restartBlink(cm) {
+ if (!cm.state.focused) return;
+ var display = cm.display;
+ clearInterval(display.blinker);
+ var on = true;
+ display.cursorDiv.style.visibility = "";
+ if (cm.options.cursorBlinkRate > 0)
+ display.blinker = setInterval(function() {
+ display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
+ }, cm.options.cursorBlinkRate);
+ else if (cm.options.cursorBlinkRate < 0)
+ display.cursorDiv.style.visibility = "hidden";
+ }
+
+ // HIGHLIGHT WORKER
+
+ function startWorker(cm, time) {
+ if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
+ cm.state.highlight.set(time, bind(highlightWorker, cm));
+ }
+
+ function highlightWorker(cm) {
+ var doc = cm.doc;
+ if (doc.frontier < doc.first) doc.frontier = doc.first;
+ if (doc.frontier >= cm.display.viewTo) return;
+ var end = +new Date + cm.options.workTime;
+ var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
+ var changedLines = [];
+
+ doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
+ if (doc.frontier >= cm.display.viewFrom) { // Visible
+ var oldStyles = line.styles;
+ var highlighted = highlightLine(cm, line, state, true);
+ line.styles = highlighted.styles;
+ var oldCls = line.styleClasses, newCls = highlighted.classes;
+ if (newCls) line.styleClasses = newCls;
+ else if (oldCls) line.styleClasses = null;
+ var ischange = !oldStyles || oldStyles.length != line.styles.length ||
+ oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
+ for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
+ if (ischange) changedLines.push(doc.frontier);
+ line.stateAfter = copyState(doc.mode, state);
+ } else {
+ processLine(cm, line.text, state);
+ line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
+ }
+ ++doc.frontier;
+ if (+new Date > end) {
+ startWorker(cm, cm.options.workDelay);
+ return true;
+ }
+ });
+ if (changedLines.length) runInOp(cm, function() {
+ for (var i = 0; i < changedLines.length; i++)
+ regLineChange(cm, changedLines[i], "text");
+ });
+ }
+
+ // Finds the line to start with when starting a parse. Tries to
+ // find a line with a stateAfter, so that it can start with a
+ // valid state. If that fails, it returns the line with the
+ // smallest indentation, which tends to need the least context to
+ // parse correctly.
+ function findStartLine(cm, n, precise) {
+ var minindent, minline, doc = cm.doc;
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
+ for (var search = n; search > lim; --search) {
+ if (search <= doc.first) return doc.first;
+ var line = getLine(doc, search - 1);
+ if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
+ var indented = countColumn(line.text, null, cm.options.tabSize);
+ if (minline == null || minindent > indented) {
+ minline = search - 1;
+ minindent = indented;
+ }
+ }
+ return minline;
+ }
+
+ function getStateBefore(cm, n, precise) {
+ var doc = cm.doc, display = cm.display;
+ if (!doc.mode.startState) return true;
+ var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
+ if (!state) state = startState(doc.mode);
+ else state = copyState(doc.mode, state);
+ doc.iter(pos, n, function(line) {
+ processLine(cm, line.text, state);
+ var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
+ line.stateAfter = save ? copyState(doc.mode, state) : null;
+ ++pos;
+ });
+ if (precise) doc.frontier = pos;
+ return state;
+ }
+
+ // POSITION MEASUREMENT
+
+ function paddingTop(display) {return display.lineSpace.offsetTop;}
+ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
+ function paddingH(display) {
+ if (display.cachedPaddingH) return display.cachedPaddingH;
+ var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
+ var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
+ if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
+ return data;
+ }
+
+ // Ensure the lineView.wrapping.heights array is populated. This is
+ // an array of bottom offsets for the lines that make up a drawn
+ // line. When lineWrapping is on, there might be more than one
+ // height.
+ function ensureLineHeights(cm, lineView, rect) {
+ var wrapping = cm.options.lineWrapping;
+ var curWidth = wrapping && cm.display.scroller.clientWidth;
+ if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
+ var heights = lineView.measure.heights = [];
+ if (wrapping) {
+ lineView.measure.width = curWidth;
+ var rects = lineView.text.firstChild.getClientRects();
+ for (var i = 0; i < rects.length - 1; i++) {
+ var cur = rects[i], next = rects[i + 1];
+ if (Math.abs(cur.bottom - next.bottom) > 2)
+ heights.push((cur.bottom + next.top) / 2 - rect.top);
+ }
+ }
+ heights.push(rect.bottom - rect.top);
+ }
+ }
+
+ // Find a line map (mapping character offsets to text nodes) and a
+ // measurement cache for the given line number. (A line view might
+ // contain multiple lines when collapsed ranges are present.)
+ function mapFromLineView(lineView, line, lineN) {
+ if (lineView.line == line)
+ return {map: lineView.measure.map, cache: lineView.measure.cache};
+ for (var i = 0; i < lineView.rest.length; i++)
+ if (lineView.rest[i] == line)
+ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
+ for (var i = 0; i < lineView.rest.length; i++)
+ if (lineNo(lineView.rest[i]) > lineN)
+ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
+ }
+
+ // Render a line into the hidden node display.externalMeasured. Used
+ // when measurement is needed for a line that's not in the viewport.
+ function updateExternalMeasurement(cm, line) {
+ line = visualLine(line);
+ var lineN = lineNo(line);
+ var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
+ view.lineN = lineN;
+ var built = view.built = buildLineContent(cm, view);
+ view.text = built.pre;
+ removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
+ return view;
+ }
+
+ // Get a {top, bottom, left, right} box (in line-local coordinates)
+ // for a given character.
+ function measureChar(cm, line, ch, bias) {
+ return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
+ }
+
+ // Find a line view that corresponds to the given line number.
+ function findViewForLine(cm, lineN) {
+ if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
+ return cm.display.view[findViewIndex(cm, lineN)];
+ var ext = cm.display.externalMeasured;
+ if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
+ return ext;
+ }
+
+ // Measurement can be split in two steps, the set-up work that
+ // applies to the whole line, and the measurement of the actual
+ // character. Functions like coordsChar, that need to do a lot of
+ // measurements in a row, can thus ensure that the set-up work is
+ // only done once.
+ function prepareMeasureForLine(cm, line) {
+ var lineN = lineNo(line);
+ var view = findViewForLine(cm, lineN);
+ if (view && !view.text)
+ view = null;
+ else if (view && view.changes)
+ updateLineForChanges(cm, view, lineN, getDimensions(cm));
+ if (!view)
+ view = updateExternalMeasurement(cm, line);
+
+ var info = mapFromLineView(view, line, lineN);
+ return {
+ line: line, view: view, rect: null,
+ map: info.map, cache: info.cache, before: info.before,
+ hasHeights: false
+ };
+ }
+
+ // Given a prepared measurement object, measures the position of an
+ // actual character (or fetches it from the cache).
+ function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
+ if (prepared.before) ch = -1;
+ var key = ch + (bias || ""), found;
+ if (prepared.cache.hasOwnProperty(key)) {
+ found = prepared.cache[key];
+ } else {
+ if (!prepared.rect)
+ prepared.rect = prepared.view.text.getBoundingClientRect();
+ if (!prepared.hasHeights) {
+ ensureLineHeights(cm, prepared.view, prepared.rect);
+ prepared.hasHeights = true;
+ }
+ found = measureCharInner(cm, prepared, ch, bias);
+ if (!found.bogus) prepared.cache[key] = found;
+ }
+ return {left: found.left, right: found.right,
+ top: varHeight ? found.rtop : found.top,
+ bottom: varHeight ? found.rbottom : found.bottom};
+ }
+
+ var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
+
+ function measureCharInner(cm, prepared, ch, bias) {
+ var map = prepared.map;
+
+ var node, start, end, collapse;
+ // First, search the line map for the text node corresponding to,
+ // or closest to, the target character.
+ for (var i = 0; i < map.length; i += 3) {
+ var mStart = map[i], mEnd = map[i + 1];
+ if (ch < mStart) {
+ start = 0; end = 1;
+ collapse = "left";
+ } else if (ch < mEnd) {
+ start = ch - mStart;
+ end = start + 1;
+ } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
+ end = mEnd - mStart;
+ start = end - 1;
+ if (ch >= mEnd) collapse = "right";
+ }
+ if (start != null) {
+ node = map[i + 2];
+ if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
+ collapse = bias;
+ if (bias == "left" && start == 0)
+ while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
+ node = map[(i -= 3) + 2];
+ collapse = "left";
+ }
+ if (bias == "right" && start == mEnd - mStart)
+ while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
+ node = map[(i += 3) + 2];
+ collapse = "right";
+ }
+ break;
+ }
+ }
+
+ var rect;
+ if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
+ for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
+ while (start && isExtendingChar(prepared.line.text.charAt(mStart + start))) --start;
+ while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end;
+ if (ie && ie_version < 9 && start == 0 && end == mEnd - mStart) {
+ rect = node.parentNode.getBoundingClientRect();
+ } else if (ie && cm.options.lineWrapping) {
+ var rects = range(node, start, end).getClientRects();
+ if (rects.length)
+ rect = rects[bias == "right" ? rects.length - 1 : 0];
+ else
+ rect = nullRect;
+ } else {
+ rect = range(node, start, end).getBoundingClientRect() || nullRect;
+ }
+ if (rect.left || rect.right || start == 0) break;
+ end = start;
+ start = start - 1;
+ collapse = "right";
+ }
+ if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
+ } else { // If it is a widget, simply get the box for the whole widget.
+ if (start > 0) collapse = bias = "right";
+ var rects;
+ if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
+ rect = rects[bias == "right" ? rects.length - 1 : 0];
+ else
+ rect = node.getBoundingClientRect();
+ }
+ if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
+ var rSpan = node.parentNode.getClientRects()[0];
+ if (rSpan)
+ rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
+ else
+ rect = nullRect;
+ }
+
+ var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
+ var mid = (rtop + rbot) / 2;
+ var heights = prepared.view.measure.heights;
+ for (var i = 0; i < heights.length - 1; i++)
+ if (mid < heights[i]) break;
+ var top = i ? heights[i - 1] : 0, bot = heights[i];
+ var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
+ right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
+ top: top, bottom: bot};
+ if (!rect.left && !rect.right) result.bogus = true;
+ if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
+
+ return result;
+ }
+
+ // Work around problem with bounding client rects on ranges being
+ // returned incorrectly when zoomed on IE10 and below.
+ function maybeUpdateRectForZooming(measure, rect) {
+ if (!window.screen || screen.logicalXDPI == null ||
+ screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
+ return rect;
+ var scaleX = screen.logicalXDPI / screen.deviceXDPI;
+ var scaleY = screen.logicalYDPI / screen.deviceYDPI;
+ return {left: rect.left * scaleX, right: rect.right * scaleX,
+ top: rect.top * scaleY, bottom: rect.bottom * scaleY};
+ }
+
+ function clearLineMeasurementCacheFor(lineView) {
+ if (lineView.measure) {
+ lineView.measure.cache = {};
+ lineView.measure.heights = null;
+ if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
+ lineView.measure.caches[i] = {};
+ }
+ }
+
+ function clearLineMeasurementCache(cm) {
+ cm.display.externalMeasure = null;
+ removeChildren(cm.display.lineMeasure);
+ for (var i = 0; i < cm.display.view.length; i++)
+ clearLineMeasurementCacheFor(cm.display.view[i]);
+ }
+
+ function clearCaches(cm) {
+ clearLineMeasurementCache(cm);
+ cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
+ if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
+ cm.display.lineNumChars = null;
+ }
+
+ function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
+ function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
+
+ // Converts a {top, bottom, left, right} box from line-local
+ // coordinates into another coordinate system. Context may be one of
+ // "line", "div" (display.lineDiv), "local"/null (editor), or "page".
+ function intoCoordSystem(cm, lineObj, rect, context) {
+ if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
+ var size = widgetHeight(lineObj.widgets[i]);
+ rect.top += size; rect.bottom += size;
+ }
+ if (context == "line") return rect;
+ if (!context) context = "local";
+ var yOff = heightAtLine(lineObj);
+ if (context == "local") yOff += paddingTop(cm.display);
+ else yOff -= cm.display.viewOffset;
+ if (context == "page" || context == "window") {
+ var lOff = cm.display.lineSpace.getBoundingClientRect();
+ yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
+ var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
+ rect.left += xOff; rect.right += xOff;
+ }
+ rect.top += yOff; rect.bottom += yOff;
+ return rect;
+ }
+
+ // Coverts a box from "div" coords to another coordinate system.
+ // Context may be "window", "page", "div", or "local"/null.
+ function fromCoordSystem(cm, coords, context) {
+ if (context == "div") return coords;
+ var left = coords.left, top = coords.top;
+ // First move into "page" coordinate system
+ if (context == "page") {
+ left -= pageScrollX();
+ top -= pageScrollY();
+ } else if (context == "local" || !context) {
+ var localBox = cm.display.sizer.getBoundingClientRect();
+ left += localBox.left;
+ top += localBox.top;
+ }
+
+ var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
+ return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
+ }
+
+ function charCoords(cm, pos, context, lineObj, bias) {
+ if (!lineObj) lineObj = getLine(cm.doc, pos.line);
+ return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
+ }
+
+ // Returns a box for a given cursor position, which may have an
+ // 'other' property containing the position of the secondary cursor
+ // on a bidi boundary.
+ function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
+ lineObj = lineObj || getLine(cm.doc, pos.line);
+ if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
+ function get(ch, right) {
+ var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
+ if (right) m.left = m.right; else m.right = m.left;
+ return intoCoordSystem(cm, lineObj, m, context);
+ }
+ function getBidi(ch, partPos) {
+ var part = order[partPos], right = part.level % 2;
+ if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
+ part = order[--partPos];
+ ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
+ right = true;
+ } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
+ part = order[++partPos];
+ ch = bidiLeft(part) - part.level % 2;
+ right = false;
+ }
+ if (right && ch == part.to && ch > part.from) return get(ch - 1);
+ return get(ch, right);
+ }
+ var order = getOrder(lineObj), ch = pos.ch;
+ if (!order) return get(ch);
+ var partPos = getBidiPartAt(order, ch);
+ var val = getBidi(ch, partPos);
+ if (bidiOther != null) val.other = getBidi(ch, bidiOther);
+ return val;
+ }
+
+ // Used to cheaply estimate the coordinates for a position. Used for
+ // intermediate scroll updates.
+ function estimateCoords(cm, pos) {
+ var left = 0, pos = clipPos(cm.doc, pos);
+ if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
+ var lineObj = getLine(cm.doc, pos.line);
+ var top = heightAtLine(lineObj) + paddingTop(cm.display);
+ return {left: left, right: left, top: top, bottom: top + lineObj.height};
+ }
+
+ // Positions returned by coordsChar contain some extra information.
+ // xRel is the relative x position of the input coordinates compared
+ // to the found position (so xRel > 0 means the coordinates are to
+ // the right of the character position, for example). When outside
+ // is true, that means the coordinates lie outside the line's
+ // vertical range.
+ function PosWithInfo(line, ch, outside, xRel) {
+ var pos = Pos(line, ch);
+ pos.xRel = xRel;
+ if (outside) pos.outside = true;
+ return pos;
+ }
+
+ // Compute the character position closest to the given coordinates.
+ // Input must be lineSpace-local ("div" coordinate system).
+ function coordsChar(cm, x, y) {
+ var doc = cm.doc;
+ y += cm.display.viewOffset;
+ if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
+ var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
+ if (lineN > last)
+ return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
+ if (x < 0) x = 0;
+
+ var lineObj = getLine(doc, lineN);
+ for (;;) {
+ var found = coordsCharInner(cm, lineObj, lineN, x, y);
+ var merged = collapsedSpanAtEnd(lineObj);
+ var mergedPos = merged && merged.find(0, true);
+ if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
+ lineN = lineNo(lineObj = mergedPos.to.line);
+ else
+ return found;
+ }
+ }
+
+ function coordsCharInner(cm, lineObj, lineNo, x, y) {
+ var innerOff = y - heightAtLine(lineObj);
+ var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
+ var preparedMeasure = prepareMeasureForLine(cm, lineObj);
+
+ function getX(ch) {
+ var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
+ wrongLine = true;
+ if (innerOff > sp.bottom) return sp.left - adjust;
+ else if (innerOff < sp.top) return sp.left + adjust;
+ else wrongLine = false;
+ return sp.left;
+ }
+
+ var bidi = getOrder(lineObj), dist = lineObj.text.length;
+ var from = lineLeft(lineObj), to = lineRight(lineObj);
+ var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
+
+ if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
+ // Do a binary search between these bounds.
+ for (;;) {
+ if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
+ var ch = x < fromX || x - fromX <= toX - x ? from : to;
+ var xDiff = x - (ch == from ? fromX : toX);
+ while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
+ var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
+ xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
+ return pos;
+ }
+ var step = Math.ceil(dist / 2), middle = from + step;
+ if (bidi) {
+ middle = from;
+ for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
+ }
+ var middleX = getX(middle);
+ if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
+ else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
+ }
+ }
+
+ var measureText;
+ // Compute the default text height.
+ function textHeight(display) {
+ if (display.cachedTextHeight != null) return display.cachedTextHeight;
+ if (measureText == null) {
+ measureText = elt("pre");
+ // Measure a bunch of lines, for browsers that compute
+ // fractional heights.
+ for (var i = 0; i < 49; ++i) {
+ measureText.appendChild(document.createTextNode("x"));
+ measureText.appendChild(elt("br"));
+ }
+ measureText.appendChild(document.createTextNode("x"));
+ }
+ removeChildrenAndAdd(display.measure, measureText);
+ var height = measureText.offsetHeight / 50;
+ if (height > 3) display.cachedTextHeight = height;
+ removeChildren(display.measure);
+ return height || 1;
+ }
+
+ // Compute the default character width.
+ function charWidth(display) {
+ if (display.cachedCharWidth != null) return display.cachedCharWidth;
+ var anchor = elt("span", "xxxxxxxxxx");
+ var pre = elt("pre", [anchor]);
+ removeChildrenAndAdd(display.measure, pre);
+ var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
+ if (width > 2) display.cachedCharWidth = width;
+ return width || 10;
+ }
+
+ // OPERATIONS
+
+ // Operations are used to wrap a series of changes to the editor
+ // state in such a way that each change won't have to update the
+ // cursor and display (which would be awkward, slow, and
+ // error-prone). Instead, display updates are batched and then all
+ // combined and executed at once.
+
+ var operationGroup = null;
+
+ var nextOpId = 0;
+ // Start a new operation.
+ function startOperation(cm) {
+ cm.curOp = {
+ cm: cm,
+ viewChanged: false, // Flag that indicates that lines might need to be redrawn
+ startHeight: cm.doc.height, // Used to detect need to update scrollbar
+ forceUpdate: false, // Used to force a redraw
+ updateInput: null, // Whether to reset the input textarea
+ typing: false, // Whether this reset should be careful to leave existing text (for compositing)
+ changeObjs: null, // Accumulated changes, for firing change events
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
+ cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
+ selectionChanged: false, // Whether the selection needs to be redrawn
+ updateMaxLine: false, // Set when the widest line needs to be determined anew
+ scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
+ scrollToPos: null, // Used to scroll to a specific position
+ id: ++nextOpId // Unique ID
+ };
+ if (operationGroup) {
+ operationGroup.ops.push(cm.curOp);
+ } else {
+ cm.curOp.ownsGroup = operationGroup = {
+ ops: [cm.curOp],
+ delayedCallbacks: []
+ };
+ }
+ }
+
+ function fireCallbacksForOps(group) {
+ // Calls delayed callbacks and cursorActivity handlers until no
+ // new ones appear
+ var callbacks = group.delayedCallbacks, i = 0;
+ do {
+ for (; i < callbacks.length; i++)
+ callbacks[i]();
+ for (var j = 0; j < group.ops.length; j++) {
+ var op = group.ops[j];
+ if (op.cursorActivityHandlers)
+ while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
+ op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
+ }
+ } while (i < callbacks.length);
+ }
+
+ // Finish an operation, updating the display and signalling delayed events
+ function endOperation(cm) {
+ var op = cm.curOp, group = op.ownsGroup;
+ if (!group) return;
+
+ try { fireCallbacksForOps(group); }
+ finally {
+ operationGroup = null;
+ for (var i = 0; i < group.ops.length; i++)
+ group.ops[i].cm.curOp = null;
+ endOperations(group);
+ }
+ }
+
+ // The DOM updates done when an operation finishes are batched so
+ // that the minimum number of relayouts are required.
+ function endOperations(group) {
+ var ops = group.ops;
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ endOperation_R1(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
+ endOperation_W1(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ endOperation_R2(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
+ endOperation_W2(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ endOperation_finish(ops[i]);
+ }
+
+ function endOperation_R1(op) {
+ var cm = op.cm, display = cm.display;
+ if (op.updateMaxLine) findMaxLine(cm);
+
+ op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
+ op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
+ op.scrollToPos.to.line >= display.viewTo) ||
+ display.maxLineChanged && cm.options.lineWrapping;
+ op.update = op.mustUpdate &&
+ new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
+ }
+
+ function endOperation_W1(op) {
+ op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
+ }
+
+ function endOperation_R2(op) {
+ var cm = op.cm, display = cm.display;
+ if (op.updatedDisplay) updateHeightsInViewport(cm);
+
+ op.barMeasure = measureForScrollbars(cm);
+
+ // If the max line changed since it was last measured, measure it,
+ // and ensure the document's width matches it.
+ // updateDisplay_W2 will use these properties to do the actual resizing
+ if (display.maxLineChanged && !cm.options.lineWrapping) {
+ op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
+ op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo +
+ scrollerCutOff - display.scroller.clientWidth);
+ }
+
+ if (op.updatedDisplay || op.selectionChanged)
+ op.newSelectionNodes = drawSelection(cm);
+ }
+
+ function endOperation_W2(op) {
+ var cm = op.cm;
+
+ if (op.adjustWidthTo != null) {
+ cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
+ if (op.maxScrollLeft < cm.doc.scrollLeft)
+ setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
+ cm.display.maxLineChanged = false;
+ }
+
+ if (op.newSelectionNodes)
+ showSelection(cm, op.newSelectionNodes);
+ if (op.updatedDisplay)
+ setDocumentHeight(cm, op.barMeasure);
+ if (op.updatedDisplay || op.startHeight != cm.doc.height)
+ updateScrollbars(cm, op.barMeasure);
+
+ if (op.selectionChanged) restartBlink(cm);
+
+ if (cm.state.focused && op.updateInput)
+ resetInput(cm, op.typing);
+ }
+
+ function endOperation_finish(op) {
+ var cm = op.cm, display = cm.display, doc = cm.doc;
+
+ if (op.adjustWidthTo != null && Math.abs(op.barMeasure.scrollWidth - cm.display.scroller.scrollWidth) > 1)
+ updateScrollbars(cm);
+
+ if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
+
+ // Abort mouse wheel delta measurement, when scrolling explicitly
+ if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
+ display.wheelStartX = display.wheelStartY = null;
+
+ // Propagate the scroll position to the actual DOM scroller
+ if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
+ var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
+ display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
+ }
+ if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
+ var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
+ display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
+ alignHorizontally(cm);
+ }
+ // If we need to scroll a specific position into view, do so.
+ if (op.scrollToPos) {
+ var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
+ clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
+ if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
+ }
+
+ // Fire events for markers that are hidden/unidden by editing or
+ // undoing
+ var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
+ if (hidden) for (var i = 0; i < hidden.length; ++i)
+ if (!hidden[i].lines.length) signal(hidden[i], "hide");
+ if (unhidden) for (var i = 0; i < unhidden.length; ++i)
+ if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
+
+ if (display.wrapper.offsetHeight)
+ doc.scrollTop = cm.display.scroller.scrollTop;
+
+ // Apply workaround for two webkit bugs
+ if (op.updatedDisplay && webkit) {
+ if (cm.options.lineWrapping)
+ checkForWebkitWidthBug(cm, op.barMeasure); // (Issue #2420)
+ if (op.barMeasure.scrollWidth > op.barMeasure.clientWidth &&
+ op.barMeasure.scrollWidth < op.barMeasure.clientWidth + 1 &&
+ !hScrollbarTakesSpace(cm))
+ updateScrollbars(cm); // (Issue #2562)
+ }
+
+ // Fire change events, and delayed event handlers
+ if (op.changeObjs)
+ signal(cm, "changes", cm, op.changeObjs);
+ }
+
+ // Run the given function in an operation
+ function runInOp(cm, f) {
+ if (cm.curOp) return f();
+ startOperation(cm);
+ try { return f(); }
+ finally { endOperation(cm); }
+ }
+ // Wraps a function in an operation. Returns the wrapped function.
+ function operation(cm, f) {
+ return function() {
+ if (cm.curOp) return f.apply(cm, arguments);
+ startOperation(cm);
+ try { return f.apply(cm, arguments); }
+ finally { endOperation(cm); }
+ };
+ }
+ // Used to add methods to editor and doc instances, wrapping them in
+ // operations.
+ function methodOp(f) {
+ return function() {
+ if (this.curOp) return f.apply(this, arguments);
+ startOperation(this);
+ try { return f.apply(this, arguments); }
+ finally { endOperation(this); }
+ };
+ }
+ function docMethodOp(f) {
+ return function() {
+ var cm = this.cm;
+ if (!cm || cm.curOp) return f.apply(this, arguments);
+ startOperation(cm);
+ try { return f.apply(this, arguments); }
+ finally { endOperation(cm); }
+ };
+ }
+
+ // VIEW TRACKING
+
+ // These objects are used to represent the visible (currently drawn)
+ // part of the document. A LineView may correspond to multiple
+ // logical lines, if those are connected by collapsed ranges.
+ function LineView(doc, line, lineN) {
+ // The starting line
+ this.line = line;
+ // Continuing lines, if any
+ this.rest = visualLineContinued(line);
+ // Number of logical lines in this visual line
+ this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
+ this.node = this.text = null;
+ this.hidden = lineIsHidden(doc, line);
+ }
+
+ // Create a range of LineView objects for the given lines.
+ function buildViewArray(cm, from, to) {
+ var array = [], nextPos;
+ for (var pos = from; pos < to; pos = nextPos) {
+ var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
+ nextPos = pos + view.size;
+ array.push(view);
+ }
+ return array;
+ }
+
+ // Updates the display.view data structure for a given change to the
+ // document. From and to are in pre-change coordinates. Lendiff is
+ // the amount of lines added or subtracted by the change. This is
+ // used for changes that span multiple lines, or change the way
+ // lines are divided into visual lines. regLineChange (below)
+ // registers single-line changes.
+ function regChange(cm, from, to, lendiff) {
+ if (from == null) from = cm.doc.first;
+ if (to == null) to = cm.doc.first + cm.doc.size;
+ if (!lendiff) lendiff = 0;
+
+ var display = cm.display;
+ if (lendiff && to < display.viewTo &&
+ (display.updateLineNumbers == null || display.updateLineNumbers > from))
+ display.updateLineNumbers = from;
+
+ cm.curOp.viewChanged = true;
+
+ if (from >= display.viewTo) { // Change after
+ if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
+ resetView(cm);
+ } else if (to <= display.viewFrom) { // Change before
+ if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
+ resetView(cm);
+ } else {
+ display.viewFrom += lendiff;
+ display.viewTo += lendiff;
+ }
+ } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
+ resetView(cm);
+ } else if (from <= display.viewFrom) { // Top overlap
+ var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
+ if (cut) {
+ display.view = display.view.slice(cut.index);
+ display.viewFrom = cut.lineN;
+ display.viewTo += lendiff;
+ } else {
+ resetView(cm);
+ }
+ } else if (to >= display.viewTo) { // Bottom overlap
+ var cut = viewCuttingPoint(cm, from, from, -1);
+ if (cut) {
+ display.view = display.view.slice(0, cut.index);
+ display.viewTo = cut.lineN;
+ } else {
+ resetView(cm);
+ }
+ } else { // Gap in the middle
+ var cutTop = viewCuttingPoint(cm, from, from, -1);
+ var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
+ if (cutTop && cutBot) {
+ display.view = display.view.slice(0, cutTop.index)
+ .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
+ .concat(display.view.slice(cutBot.index));
+ display.viewTo += lendiff;
+ } else {
+ resetView(cm);
+ }
+ }
+
+ var ext = display.externalMeasured;
+ if (ext) {
+ if (to < ext.lineN)
+ ext.lineN += lendiff;
+ else if (from < ext.lineN + ext.size)
+ display.externalMeasured = null;
+ }
+ }
+
+ // Register a change to a single line. Type must be one of "text",
+ // "gutter", "class", "widget"
+ function regLineChange(cm, line, type) {
+ cm.curOp.viewChanged = true;
+ var display = cm.display, ext = cm.display.externalMeasured;
+ if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
+ display.externalMeasured = null;
+
+ if (line < display.viewFrom || line >= display.viewTo) return;
+ var lineView = display.view[findViewIndex(cm, line)];
+ if (lineView.node == null) return;
+ var arr = lineView.changes || (lineView.changes = []);
+ if (indexOf(arr, type) == -1) arr.push(type);
+ }
+
+ // Clear the view.
+ function resetView(cm) {
+ cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
+ cm.display.view = [];
+ cm.display.viewOffset = 0;
+ }
+
+ // Find the view element corresponding to a given line. Return null
+ // when the line isn't visible.
+ function findViewIndex(cm, n) {
+ if (n >= cm.display.viewTo) return null;
+ n -= cm.display.viewFrom;
+ if (n < 0) return null;
+ var view = cm.display.view;
+ for (var i = 0; i < view.length; i++) {
+ n -= view[i].size;
+ if (n < 0) return i;
+ }
+ }
+
+ function viewCuttingPoint(cm, oldN, newN, dir) {
+ var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
+ if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
+ return {index: index, lineN: newN};
+ for (var i = 0, n = cm.display.viewFrom; i < index; i++)
+ n += view[i].size;
+ if (n != oldN) {
+ if (dir > 0) {
+ if (index == view.length - 1) return null;
+ diff = (n + view[index].size) - oldN;
+ index++;
+ } else {
+ diff = n - oldN;
+ }
+ oldN += diff; newN += diff;
+ }
+ while (visualLineNo(cm.doc, newN) != newN) {
+ if (index == (dir < 0 ? 0 : view.length - 1)) return null;
+ newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
+ index += dir;
+ }
+ return {index: index, lineN: newN};
+ }
+
+ // Force the view to cover a given range, adding empty view element
+ // or clipping off existing ones as needed.
+ function adjustView(cm, from, to) {
+ var display = cm.display, view = display.view;
+ if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
+ display.view = buildViewArray(cm, from, to);
+ display.viewFrom = from;
+ } else {
+ if (display.viewFrom > from)
+ display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
+ else if (display.viewFrom < from)
+ display.view = display.view.slice(findViewIndex(cm, from));
+ display.viewFrom = from;
+ if (display.viewTo < to)
+ display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
+ else if (display.viewTo > to)
+ display.view = display.view.slice(0, findViewIndex(cm, to));
+ }
+ display.viewTo = to;
+ }
+
+ // Count the number of lines in the view whose DOM representation is
+ // out of date (or nonexistent).
+ function countDirtyView(cm) {
+ var view = cm.display.view, dirty = 0;
+ for (var i = 0; i < view.length; i++) {
+ var lineView = view[i];
+ if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
+ }
+ return dirty;
+ }
+
+ // INPUT HANDLING
+
+ // Poll for input changes, using the normal rate of polling. This
+ // runs as long as the editor is focused.
+ function slowPoll(cm) {
+ if (cm.display.pollingFast) return;
+ cm.display.poll.set(cm.options.pollInterval, function() {
+ readInput(cm);
+ if (cm.state.focused) slowPoll(cm);
+ });
+ }
+
+ // When an event has just come in that is likely to add or change
+ // something in the input textarea, we poll faster, to ensure that
+ // the change appears on the screen quickly.
+ function fastPoll(cm) {
+ var missed = false;
+ cm.display.pollingFast = true;
+ function p() {
+ var changed = readInput(cm);
+ if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
+ else {cm.display.pollingFast = false; slowPoll(cm);}
+ }
+ cm.display.poll.set(20, p);
+ }
+
+ // This will be set to an array of strings when copying, so that,
+ // when pasting, we know what kind of selections the copied text
+ // was made out of.
+ var lastCopied = null;
+
+ // Read input from the textarea, and update the document to match.
+ // When something is selected, it is present in the textarea, and
+ // selected (unless it is huge, in which case a placeholder is
+ // used). When nothing is selected, the cursor sits after previously
+ // seen text (can be empty), which is stored in prevInput (we must
+ // not reset the textarea when typing, because that breaks IME).
+ function readInput(cm) {
+ var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc;
+ // Since this is called a *lot*, try to bail out as cheaply as
+ // possible when it is clear that nothing happened. hasSelection
+ // will be the case when there is a lot of text in the textarea,
+ // in which case reading its value would be expensive.
+ if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput)
+ return false;
+ // See paste handler for more on the fakedLastChar kludge
+ if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
+ input.value = input.value.substring(0, input.value.length - 1);
+ cm.state.fakedLastChar = false;
+ }
+ var text = input.value;
+ // If nothing changed, bail.
+ if (text == prevInput && !cm.somethingSelected()) return false;
+ // Work around nonsensical selection resetting in IE9/10, and
+ // inexplicable appearance of private area unicode characters on
+ // some key combos in Mac (#2689).
+ if (ie && ie_version >= 9 && cm.display.inputHasSelection === text ||
+ mac && /[\uf700-\uf7ff]/.test(text)) {
+ resetInput(cm);
+ return false;
+ }
+
+ var withOp = !cm.curOp;
+ if (withOp) startOperation(cm);
+ cm.display.shift = false;
+
+ if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu && !prevInput)
+ prevInput = "\u200b";
+ // Find the part of the input that is actually new
+ var same = 0, l = Math.min(prevInput.length, text.length);
+ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
+ var inserted = text.slice(same), textLines = splitLines(inserted);
+
+ // When pasing N lines into N selections, insert one line per selection
+ var multiPaste = null;
+ if (cm.state.pasteIncoming && doc.sel.ranges.length > 1) {
+ if (lastCopied && lastCopied.join("\n") == inserted)
+ multiPaste = doc.sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);
+ else if (textLines.length == doc.sel.ranges.length)
+ multiPaste = map(textLines, function(l) { return [l]; });
+ }
+
+ // Normal behavior is to insert the new text into every selection
+ for (var i = doc.sel.ranges.length - 1; i >= 0; i--) {
+ var range = doc.sel.ranges[i];
+ var from = range.from(), to = range.to();
+ // Handle deletion
+ if (same < prevInput.length)
+ from = Pos(from.line, from.ch - (prevInput.length - same));
+ // Handle overwrite
+ else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming)
+ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
+ var updateInput = cm.curOp.updateInput;
+ var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
+ origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
+ makeChange(cm.doc, changeEvent);
+ signalLater(cm, "inputRead", cm, changeEvent);
+ // When an 'electric' character is inserted, immediately trigger a reindent
+ if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
+ cm.options.smartIndent && range.head.ch < 100 &&
+ (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
+ var mode = cm.getModeAt(range.head);
+ var end = changeEnd(changeEvent);
+ if (mode.electricChars) {
+ for (var j = 0; j < mode.electricChars.length; j++)
+ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
+ indentLine(cm, end.line, "smart");
+ break;
+ }
+ } else if (mode.electricInput) {
+ if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
+ indentLine(cm, end.line, "smart");
+ }
+ }
+ }
+ ensureCursorVisible(cm);
+ cm.curOp.updateInput = updateInput;
+ cm.curOp.typing = true;
+
+ // Don't leave long text in the textarea, since it makes further polling slow
+ if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
+ else cm.display.prevInput = text;
+ if (withOp) endOperation(cm);
+ cm.state.pasteIncoming = cm.state.cutIncoming = false;
+ return true;
+ }
+
+ // Reset the input to correspond to the selection (or to be empty,
+ // when not typing and nothing is selected)
+ function resetInput(cm, typing) {
+ var minimal, selected, doc = cm.doc;
+ if (cm.somethingSelected()) {
+ cm.display.prevInput = "";
+ var range = doc.sel.primary();
+ minimal = hasCopyEvent &&
+ (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
+ var content = minimal ? "-" : selected || cm.getSelection();
+ cm.display.input.value = content;
+ if (cm.state.focused) selectInput(cm.display.input);
+ if (ie && ie_version >= 9) cm.display.inputHasSelection = content;
+ } else if (!typing) {
+ cm.display.prevInput = cm.display.input.value = "";
+ if (ie && ie_version >= 9) cm.display.inputHasSelection = null;
+ }
+ cm.display.inaccurateSelection = minimal;
+ }
+
+ function focusInput(cm) {
+ if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input))
+ cm.display.input.focus();
+ }
+
+ function ensureFocus(cm) {
+ if (!cm.state.focused) { focusInput(cm); onFocus(cm); }
+ }
+
+ function isReadOnly(cm) {
+ return cm.options.readOnly || cm.doc.cantEdit;
+ }
+
+ // EVENT HANDLERS
+
+ // Attach the necessary event handlers when initializing the editor
+ function registerEventHandlers(cm) {
+ var d = cm.display;
+ on(d.scroller, "mousedown", operation(cm, onMouseDown));
+ // Older IE's will not fire a second mousedown for a double click
+ if (ie && ie_version < 11)
+ on(d.scroller, "dblclick", operation(cm, function(e) {
+ if (signalDOMEvent(cm, e)) return;
+ var pos = posFromMouse(cm, e);
+ if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
+ e_preventDefault(e);
+ var word = cm.findWordAt(pos);
+ extendSelection(cm.doc, word.anchor, word.head);
+ }));
+ else
+ on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
+ // Prevent normal selection in the editor (we handle our own)
+ on(d.lineSpace, "selectstart", function(e) {
+ if (!eventInWidget(d, e)) e_preventDefault(e);
+ });
+ // Some browsers fire contextmenu *after* opening the menu, at
+ // which point we can't mess with it anymore. Context menu is
+ // handled in onMouseDown for these browsers.
+ if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
+
+ // Sync scrolling between fake scrollbars and real scrollable
+ // area, ensure viewport is updated when scrolling.
+ on(d.scroller, "scroll", function() {
+ if (d.scroller.clientHeight) {
+ setScrollTop(cm, d.scroller.scrollTop);
+ setScrollLeft(cm, d.scroller.scrollLeft, true);
+ signal(cm, "scroll", cm);
+ }
+ });
+ on(d.scrollbarV, "scroll", function() {
+ if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
+ });
+ on(d.scrollbarH, "scroll", function() {
+ if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
+ });
+
+ // Listen to wheel events in order to try and update the viewport on time.
+ on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
+ on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
+
+ // Prevent clicks in the scrollbars from killing focus
+ function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
+ on(d.scrollbarH, "mousedown", reFocus);
+ on(d.scrollbarV, "mousedown", reFocus);
+ // Prevent wrapper from ever scrolling
+ on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
+
+ on(d.input, "keyup", function(e) { onKeyUp.call(cm, e); });
+ on(d.input, "input", function() {
+ if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
+ fastPoll(cm);
+ });
+ on(d.input, "keydown", operation(cm, onKeyDown));
+ on(d.input, "keypress", operation(cm, onKeyPress));
+ on(d.input, "focus", bind(onFocus, cm));
+ on(d.input, "blur", bind(onBlur, cm));
+
+ function drag_(e) {
+ if (!signalDOMEvent(cm, e)) e_stop(e);
+ }
+ if (cm.options.dragDrop) {
+ on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
+ on(d.scroller, "dragenter", drag_);
+ on(d.scroller, "dragover", drag_);
+ on(d.scroller, "drop", operation(cm, onDrop));
+ }
+ on(d.scroller, "paste", function(e) {
+ if (eventInWidget(d, e)) return;
+ cm.state.pasteIncoming = true;
+ focusInput(cm);
+ fastPoll(cm);
+ });
+ on(d.input, "paste", function() {
+ // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
+ // Add a char to the end of textarea before paste occur so that
+ // selection doesn't span to the end of textarea.
+ if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
+ var start = d.input.selectionStart, end = d.input.selectionEnd;
+ d.input.value += "$";
+ // The selection end needs to be set before the start, otherwise there
+ // can be an intermediate non-empty selection between the two, which
+ // can override the middle-click paste buffer on linux and cause the
+ // wrong thing to get pasted.
+ d.input.selectionEnd = end;
+ d.input.selectionStart = start;
+ cm.state.fakedLastChar = true;
+ }
+ cm.state.pasteIncoming = true;
+ fastPoll(cm);
+ });
+
+ function prepareCopyCut(e) {
+ if (cm.somethingSelected()) {
+ lastCopied = cm.getSelections();
+ if (d.inaccurateSelection) {
+ d.prevInput = "";
+ d.inaccurateSelection = false;
+ d.input.value = lastCopied.join("\n");
+ selectInput(d.input);
+ }
+ } else {
+ var text = [], ranges = [];
+ for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
+ var line = cm.doc.sel.ranges[i].head.line;
+ var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
+ ranges.push(lineRange);
+ text.push(cm.getRange(lineRange.anchor, lineRange.head));
+ }
+ if (e.type == "cut") {
+ cm.setSelections(ranges, null, sel_dontScroll);
+ } else {
+ d.prevInput = "";
+ d.input.value = text.join("\n");
+ selectInput(d.input);
+ }
+ lastCopied = text;
+ }
+ if (e.type == "cut") cm.state.cutIncoming = true;
+ }
+ on(d.input, "cut", prepareCopyCut);
+ on(d.input, "copy", prepareCopyCut);
+
+ // Needed to handle Tab key in KHTML
+ if (khtml) on(d.sizer, "mouseup", function() {
+ if (activeElt() == d.input) d.input.blur();
+ focusInput(cm);
+ });
+ }
+
+ // Called when the window resizes
+ function onResize(cm) {
+ // Might be a text scaling operation, clear size caches.
+ var d = cm.display;
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+ cm.setSize();
+ }
+
+ // MOUSE EVENTS
+
+ // Return true when the given mouse event happened in a widget
+ function eventInWidget(display, e) {
+ for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
+ if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
+ }
+ }
+
+ // Given a mouse event, find the corresponding position. If liberal
+ // is false, it checks whether a gutter or scrollbar was clicked,
+ // and returns null if it was. forRect is used by rectangular
+ // selections, and tries to estimate a character position even for
+ // coordinates beyond the right of the text.
+ function posFromMouse(cm, e, liberal, forRect) {
+ var display = cm.display;
+ if (!liberal) {
+ var target = e_target(e);
+ if (target == display.scrollbarH || target == display.scrollbarV ||
+ target == display.scrollbarFiller || target == display.gutterFiller) return null;
+ }
+ var x, y, space = display.lineSpace.getBoundingClientRect();
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
+ try { x = e.clientX - space.left; y = e.clientY - space.top; }
+ catch (e) { return null; }
+ var coords = coordsChar(cm, x, y), line;
+ if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
+ var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
+ }
+ return coords;
+ }
+
+ // A mouse down can be a single click, double click, triple click,
+ // start of selection drag, start of text drag, new cursor
+ // (ctrl-click), rectangle drag (alt-drag), or xwin
+ // middle-click-paste. Or it might be a click on something we should
+ // not interfere with, such as a scrollbar or widget.
+ function onMouseDown(e) {
+ if (signalDOMEvent(this, e)) return;
+ var cm = this, display = cm.display;
+ display.shift = e.shiftKey;
+
+ if (eventInWidget(display, e)) {
+ if (!webkit) {
+ // Briefly turn off draggability, to allow widgets to do
+ // normal dragging things.
+ display.scroller.draggable = false;
+ setTimeout(function(){display.scroller.draggable = true;}, 100);
+ }
+ return;
+ }
+ if (clickInGutter(cm, e)) return;
+ var start = posFromMouse(cm, e);
+ window.focus();
+
+ switch (e_button(e)) {
+ case 1:
+ if (start)
+ leftButtonDown(cm, e, start);
+ else if (e_target(e) == display.scroller)
+ e_preventDefault(e);
+ break;
+ case 2:
+ if (webkit) cm.state.lastMiddleDown = +new Date;
+ if (start) extendSelection(cm.doc, start);
+ setTimeout(bind(focusInput, cm), 20);
+ e_preventDefault(e);
+ break;
+ case 3:
+ if (captureRightClick) onContextMenu(cm, e);
+ break;
+ }
+ }
+
+ var lastClick, lastDoubleClick;
+ function leftButtonDown(cm, e, start) {
+ setTimeout(bind(ensureFocus, cm), 0);
+
+ var now = +new Date, type;
+ if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
+ type = "triple";
+ } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
+ type = "double";
+ lastDoubleClick = {time: now, pos: start};
+ } else {
+ type = "single";
+ lastClick = {time: now, pos: start};
+ }
+
+ var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
+ if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
+ type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
+ leftButtonStartDrag(cm, e, start, modifier);
+ else
+ leftButtonSelect(cm, e, start, type, modifier);
+ }
+
+ // Start a text drag. When it ends, see if any dragging actually
+ // happen, and treat as a click if it didn't.
+ function leftButtonStartDrag(cm, e, start, modifier) {
+ var display = cm.display;
+ var dragEnd = operation(cm, function(e2) {
+ if (webkit) display.scroller.draggable = false;
+ cm.state.draggingText = false;
+ off(document, "mouseup", dragEnd);
+ off(display.scroller, "drop", dragEnd);
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
+ e_preventDefault(e2);
+ if (!modifier)
+ extendSelection(cm.doc, start);
+ focusInput(cm);
+ // Work around unexplainable focus problem in IE9 (#2127)
+ if (ie && ie_version == 9)
+ setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
+ }
+ });
+ // Let the drag handler handle this.
+ if (webkit) display.scroller.draggable = true;
+ cm.state.draggingText = dragEnd;
+ // IE's approach to draggable
+ if (display.scroller.dragDrop) display.scroller.dragDrop();
+ on(document, "mouseup", dragEnd);
+ on(display.scroller, "drop", dragEnd);
+ }
+
+ // Normal selection, as opposed to text dragging.
+ function leftButtonSelect(cm, e, start, type, addNew) {
+ var display = cm.display, doc = cm.doc;
+ e_preventDefault(e);
+
+ var ourRange, ourIndex, startSel = doc.sel;
+ if (addNew && !e.shiftKey) {
+ ourIndex = doc.sel.contains(start);
+ if (ourIndex > -1)
+ ourRange = doc.sel.ranges[ourIndex];
+ else
+ ourRange = new Range(start, start);
+ } else {
+ ourRange = doc.sel.primary();
+ }
+
+ if (e.altKey) {
+ type = "rect";
+ if (!addNew) ourRange = new Range(start, start);
+ start = posFromMouse(cm, e, true, true);
+ ourIndex = -1;
+ } else if (type == "double") {
+ var word = cm.findWordAt(start);
+ if (cm.display.shift || doc.extend)
+ ourRange = extendRange(doc, ourRange, word.anchor, word.head);
+ else
+ ourRange = word;
+ } else if (type == "triple") {
+ var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
+ if (cm.display.shift || doc.extend)
+ ourRange = extendRange(doc, ourRange, line.anchor, line.head);
+ else
+ ourRange = line;
+ } else {
+ ourRange = extendRange(doc, ourRange, start);
+ }
+
+ if (!addNew) {
+ ourIndex = 0;
+ setSelection(doc, new Selection([ourRange], 0), sel_mouse);
+ startSel = doc.sel;
+ } else if (ourIndex > -1) {
+ replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
+ } else {
+ ourIndex = doc.sel.ranges.length;
+ setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
+ {scroll: false, origin: "*mouse"});
+ }
+
+ var lastPos = start;
+ function extendTo(pos) {
+ if (cmp(lastPos, pos) == 0) return;
+ lastPos = pos;
+
+ if (type == "rect") {
+ var ranges = [], tabSize = cm.options.tabSize;
+ var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
+ var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
+ var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
+ for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
+ line <= end; line++) {
+ var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
+ if (left == right)
+ ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
+ else if (text.length > leftPos)
+ ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
+ }
+ if (!ranges.length) ranges.push(new Range(start, start));
+ setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
+ {origin: "*mouse", scroll: false});
+ cm.scrollIntoView(pos);
+ } else {
+ var oldRange = ourRange;
+ var anchor = oldRange.anchor, head = pos;
+ if (type != "single") {
+ if (type == "double")
+ var range = cm.findWordAt(pos);
+ else
+ var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
+ if (cmp(range.anchor, anchor) > 0) {
+ head = range.head;
+ anchor = minPos(oldRange.from(), range.anchor);
+ } else {
+ head = range.anchor;
+ anchor = maxPos(oldRange.to(), range.head);
+ }
+ }
+ var ranges = startSel.ranges.slice(0);
+ ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
+ setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
+ }
+ }
+
+ var editorSize = display.wrapper.getBoundingClientRect();
+ // Used to ensure timeout re-tries don't fire when another extend
+ // happened in the meantime (clearTimeout isn't reliable -- at
+ // least on Chrome, the timeouts still happen even when cleared,
+ // if the clear happens after their scheduled firing time).
+ var counter = 0;
+
+ function extend(e) {
+ var curCount = ++counter;
+ var cur = posFromMouse(cm, e, true, type == "rect");
+ if (!cur) return;
+ if (cmp(cur, lastPos) != 0) {
+ ensureFocus(cm);
+ extendTo(cur);
+ var visible = visibleLines(display, doc);
+ if (cur.line >= visible.to || cur.line < visible.from)
+ setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
+ } else {
+ var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
+ if (outside) setTimeout(operation(cm, function() {
+ if (counter != curCount) return;
+ display.scroller.scrollTop += outside;
+ extend(e);
+ }), 50);
+ }
+ }
+
+ function done(e) {
+ counter = Infinity;
+ e_preventDefault(e);
+ focusInput(cm);
+ off(document, "mousemove", move);
+ off(document, "mouseup", up);
+ doc.history.lastSelOrigin = null;
+ }
+
+ var move = operation(cm, function(e) {
+ if (!e_button(e)) done(e);
+ else extend(e);
+ });
+ var up = operation(cm, done);
+ on(document, "mousemove", move);
+ on(document, "mouseup", up);
+ }
+
+ // Determines whether an event happened in the gutter, and fires the
+ // handlers for the corresponding event.
+ function gutterEvent(cm, e, type, prevent, signalfn) {
+ try { var mX = e.clientX, mY = e.clientY; }
+ catch(e) { return false; }
+ if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
+ if (prevent) e_preventDefault(e);
+
+ var display = cm.display;
+ var lineBox = display.lineDiv.getBoundingClientRect();
+
+ if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
+ mY -= lineBox.top - display.viewOffset;
+
+ for (var i = 0; i < cm.options.gutters.length; ++i) {
+ var g = display.gutters.childNodes[i];
+ if (g && g.getBoundingClientRect().right >= mX) {
+ var line = lineAtHeight(cm.doc, mY);
+ var gutter = cm.options.gutters[i];
+ signalfn(cm, type, cm, line, gutter, e);
+ return e_defaultPrevented(e);
+ }
+ }
+ }
+
+ function clickInGutter(cm, e) {
+ return gutterEvent(cm, e, "gutterClick", true, signalLater);
+ }
+
+ // Kludge to work around strange IE behavior where it'll sometimes
+ // re-fire a series of drag-related events right after the drop (#1551)
+ var lastDrop = 0;
+
+ function onDrop(e) {
+ var cm = this;
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
+ return;
+ e_preventDefault(e);
+ if (ie) lastDrop = +new Date;
+ var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
+ if (!pos || isReadOnly(cm)) return;
+ // Might be a file drop, in which case we simply extract the text
+ // and insert it.
+ if (files && files.length && window.FileReader && window.File) {
+ var n = files.length, text = Array(n), read = 0;
+ var loadFile = function(file, i) {
+ var reader = new FileReader;
+ reader.onload = operation(cm, function() {
+ text[i] = reader.result;
+ if (++read == n) {
+ pos = clipPos(cm.doc, pos);
+ var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
+ makeChange(cm.doc, change);
+ setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
+ }
+ });
+ reader.readAsText(file);
+ };
+ for (var i = 0; i < n; ++i) loadFile(files[i], i);
+ } else { // Normal drop
+ // Don't do a replace if the drop happened inside of the selected text.
+ if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
+ cm.state.draggingText(e);
+ // Ensure the editor is re-focused
+ setTimeout(bind(focusInput, cm), 20);
+ return;
+ }
+ try {
+ var text = e.dataTransfer.getData("Text");
+ if (text) {
+ if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey))
+ var selected = cm.listSelections();
+ setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
+ if (selected) for (var i = 0; i < selected.length; ++i)
+ replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
+ cm.replaceSelection(text, "around", "paste");
+ focusInput(cm);
+ }
+ }
+ catch(e){}
+ }
+ }
+
+ function onDragStart(cm, e) {
+ if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
+
+ e.dataTransfer.setData("Text", cm.getSelection());
+
+ // Use dummy image instead of default browsers image.
+ // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
+ if (e.dataTransfer.setDragImage && !safari) {
+ var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
+ img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
+ if (presto) {
+ img.width = img.height = 1;
+ cm.display.wrapper.appendChild(img);
+ // Force a relayout, or Opera won't use our image for some obscure reason
+ img._top = img.offsetTop;
+ }
+ e.dataTransfer.setDragImage(img, 0, 0);
+ if (presto) img.parentNode.removeChild(img);
+ }
+ }
+
+ // SCROLL EVENTS
+
+ // Sync the scrollable area and scrollbars, ensure the viewport
+ // covers the visible area.
+ function setScrollTop(cm, val) {
+ if (Math.abs(cm.doc.scrollTop - val) < 2) return;
+ cm.doc.scrollTop = val;
+ if (!gecko) updateDisplaySimple(cm, {top: val});
+ if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
+ if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
+ if (gecko) updateDisplaySimple(cm);
+ startWorker(cm, 100);
+ }
+ // Sync scroller and scrollbar, ensure the gutter elements are
+ // aligned.
+ function setScrollLeft(cm, val, isScroller) {
+ if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
+ val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
+ cm.doc.scrollLeft = val;
+ alignHorizontally(cm);
+ if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
+ if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
+ }
+
+ // Since the delta values reported on mouse wheel events are
+ // unstandardized between browsers and even browser versions, and
+ // generally horribly unpredictable, this code starts by measuring
+ // the scroll effect that the first few mouse wheel events have,
+ // and, from that, detects the way it can convert deltas to pixel
+ // offsets afterwards.
+ //
+ // The reason we want to know the amount a wheel event will scroll
+ // is that it gives us a chance to update the display before the
+ // actual scrolling happens, reducing flickering.
+
+ var wheelSamples = 0, wheelPixelsPerUnit = null;
+ // Fill in a browser-detected starting value on browsers where we
+ // know one. These don't have to be accurate -- the result of them
+ // being wrong would just be a slight flicker on the first wheel
+ // scroll (if it is large enough).
+ if (ie) wheelPixelsPerUnit = -.53;
+ else if (gecko) wheelPixelsPerUnit = 15;
+ else if (chrome) wheelPixelsPerUnit = -.7;
+ else if (safari) wheelPixelsPerUnit = -1/3;
+
+ function onScrollWheel(cm, e) {
+ var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
+ if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
+ if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
+ else if (dy == null) dy = e.wheelDelta;
+
+ var display = cm.display, scroll = display.scroller;
+ // Quit if there's nothing to scroll here
+ if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
+ dy && scroll.scrollHeight > scroll.clientHeight)) return;
+
+ // Webkit browsers on OS X abort momentum scrolls when the target
+ // of the scroll event is removed from the scrollable element.
+ // This hack (see related code in patchDisplay) makes sure the
+ // element is kept around.
+ if (dy && mac && webkit) {
+ outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
+ for (var i = 0; i < view.length; i++) {
+ if (view[i].node == cur) {
+ cm.display.currentWheelTarget = cur;
+ break outer;
+ }
+ }
+ }
+ }
+
+ // On some browsers, horizontal scrolling will cause redraws to
+ // happen before the gutter has been realigned, causing it to
+ // wriggle around in a most unseemly way. When we have an
+ // estimated pixels/delta value, we just handle horizontal
+ // scrolling entirely here. It'll be slightly off from native, but
+ // better than glitching out.
+ if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
+ if (dy)
+ setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
+ setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
+ e_preventDefault(e);
+ display.wheelStartX = null; // Abort measurement, if in progress
+ return;
+ }
+
+ // 'Project' the visible viewport to cover the area that is being
+ // scrolled into view (if we know enough to estimate it).
+ if (dy && wheelPixelsPerUnit != null) {
+ var pixels = dy * wheelPixelsPerUnit;
+ var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
+ if (pixels < 0) top = Math.max(0, top + pixels - 50);
+ else bot = Math.min(cm.doc.height, bot + pixels + 50);
+ updateDisplaySimple(cm, {top: top, bottom: bot});
+ }
+
+ if (wheelSamples < 20) {
+ if (display.wheelStartX == null) {
+ display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
+ display.wheelDX = dx; display.wheelDY = dy;
+ setTimeout(function() {
+ if (display.wheelStartX == null) return;
+ var movedX = scroll.scrollLeft - display.wheelStartX;
+ var movedY = scroll.scrollTop - display.wheelStartY;
+ var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
+ (movedX && display.wheelDX && movedX / display.wheelDX);
+ display.wheelStartX = display.wheelStartY = null;
+ if (!sample) return;
+ wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
+ ++wheelSamples;
+ }, 200);
+ } else {
+ display.wheelDX += dx; display.wheelDY += dy;
+ }
+ }
+ }
+
+ // KEY EVENTS
+
+ // Run a handler that was bound to a key.
+ function doHandleBinding(cm, bound, dropShift) {
+ if (typeof bound == "string") {
+ bound = commands[bound];
+ if (!bound) return false;
+ }
+ // Ensure previous input has been read, so that the handler sees a
+ // consistent view of the document
+ if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
+ var prevShift = cm.display.shift, done = false;
+ try {
+ if (isReadOnly(cm)) cm.state.suppressEdits = true;
+ if (dropShift) cm.display.shift = false;
+ done = bound(cm) != Pass;
+ } finally {
+ cm.display.shift = prevShift;
+ cm.state.suppressEdits = false;
+ }
+ return done;
+ }
+
+ // Collect the currently active keymaps.
+ function allKeyMaps(cm) {
+ var maps = cm.state.keyMaps.slice(0);
+ if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
+ maps.push(cm.options.keyMap);
+ return maps;
+ }
+
+ var maybeTransition;
+ // Handle a key from the keydown event.
+ function handleKeyBinding(cm, e) {
+ // Handle automatic keymap transitions
+ var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
+ clearTimeout(maybeTransition);
+ if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
+ if (getKeyMap(cm.options.keyMap) == startMap) {
+ cm.options.keyMap = (next.call ? next.call(null, cm) : next);
+ keyMapChanged(cm);
+ }
+ }, 50);
+
+ var name = keyName(e, true), handled = false;
+ if (!name) return false;
+ var keymaps = allKeyMaps(cm);
+
+ if (e.shiftKey) {
+ // First try to resolve full name (including 'Shift-'). Failing
+ // that, see if there is a cursor-motion command (starting with
+ // 'go') bound to the keyname without 'Shift-'.
+ handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
+ || lookupKey(name, keymaps, function(b) {
+ if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
+ return doHandleBinding(cm, b);
+ });
+ } else {
+ handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
+ }
+
+ if (handled) {
+ e_preventDefault(e);
+ restartBlink(cm);
+ signalLater(cm, "keyHandled", cm, name, e);
+ }
+ return handled;
+ }
+
+ // Handle a key from the keypress event
+ function handleCharBinding(cm, e, ch) {
+ var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
+ function(b) { return doHandleBinding(cm, b, true); });
+ if (handled) {
+ e_preventDefault(e);
+ restartBlink(cm);
+ signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
+ }
+ return handled;
+ }
+
+ var lastStoppedKey = null;
+ function onKeyDown(e) {
+ var cm = this;
+ ensureFocus(cm);
+ if (signalDOMEvent(cm, e)) return;
+ // IE does strange things with escape.
+ if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
+ var code = e.keyCode;
+ cm.display.shift = code == 16 || e.shiftKey;
+ var handled = handleKeyBinding(cm, e);
+ if (presto) {
+ lastStoppedKey = handled ? code : null;
+ // Opera has no cut event... we try to at least catch the key combo
+ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
+ cm.replaceSelection("", null, "cut");
+ }
+
+ // Turn mouse into crosshair when Alt is held on Mac.
+ if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
+ showCrossHair(cm);
+ }
+
+ function showCrossHair(cm) {
+ var lineDiv = cm.display.lineDiv;
+ addClass(lineDiv, "CodeMirror-crosshair");
+
+ function up(e) {
+ if (e.keyCode == 18 || !e.altKey) {
+ rmClass(lineDiv, "CodeMirror-crosshair");
+ off(document, "keyup", up);
+ off(document, "mouseover", up);
+ }
+ }
+ on(document, "keyup", up);
+ on(document, "mouseover", up);
+ }
+
+ function onKeyUp(e) {
+ if (e.keyCode == 16) this.doc.sel.shift = false;
+ signalDOMEvent(this, e);
+ }
+
+ function onKeyPress(e) {
+ var cm = this;
+ if (signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
+ var keyCode = e.keyCode, charCode = e.charCode;
+ if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
+ if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
+ if (handleCharBinding(cm, e, ch)) return;
+ if (ie && ie_version >= 9) cm.display.inputHasSelection = null;
+ fastPoll(cm);
+ }
+
+ // FOCUS/BLUR EVENTS
+
+ function onFocus(cm) {
+ if (cm.options.readOnly == "nocursor") return;
+ if (!cm.state.focused) {
+ signal(cm, "focus", cm);
+ cm.state.focused = true;
+ addClass(cm.display.wrapper, "CodeMirror-focused");
+ // The prevInput test prevents this from firing when a context
+ // menu is closed (since the resetInput would kill the
+ // select-all detection hack)
+ if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
+ resetInput(cm);
+ if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
+ }
+ }
+ slowPoll(cm);
+ restartBlink(cm);
+ }
+ function onBlur(cm) {
+ if (cm.state.focused) {
+ signal(cm, "blur", cm);
+ cm.state.focused = false;
+ rmClass(cm.display.wrapper, "CodeMirror-focused");
+ }
+ clearInterval(cm.display.blinker);
+ setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
+ }
+
+ // CONTEXT MENU HANDLING
+
+ // To make the context menu work, we need to briefly unhide the
+ // textarea (making it as unobtrusive as possible) to let the
+ // right-click take effect on it.
+ function onContextMenu(cm, e) {
+ if (signalDOMEvent(cm, e, "contextmenu")) return;
+ var display = cm.display;
+ if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
+
+ var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
+ if (!pos || presto) return; // Opera is difficult.
+
+ // Reset the current text selection only if the click is done outside of the selection
+ // and 'resetSelectionOnContextMenu' option is true.
+ var reset = cm.options.resetSelectionOnContextMenu;
+ if (reset && cm.doc.sel.contains(pos) == -1)
+ operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
+
+ var oldCSS = display.input.style.cssText;
+ display.inputDiv.style.position = "absolute";
+ display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
+ (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
+ "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
+ if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
+ focusInput(cm);
+ if (webkit) window.scrollTo(null, oldScrollY);
+ resetInput(cm);
+ // Adds "Select all" to context menu in FF
+ if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
+ display.selForContextMenu = cm.doc.sel;
+ clearTimeout(display.detectingSelectAll);
+
+ // Select-all will be greyed out if there's nothing to select, so
+ // this adds a zero-width space so that we can later check whether
+ // it got selected.
+ function prepareSelectAllHack() {
+ if (display.input.selectionStart != null) {
+ var selected = cm.somethingSelected();
+ var extval = display.input.value = "\u200b" + (selected ? display.input.value : "");
+ display.prevInput = selected ? "" : "\u200b";
+ display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
+ // Re-set this, in case some other handler touched the
+ // selection in the meantime.
+ display.selForContextMenu = cm.doc.sel;
+ }
+ }
+ function rehide() {
+ display.inputDiv.style.position = "relative";
+ display.input.style.cssText = oldCSS;
+ if (ie && ie_version < 9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
+ slowPoll(cm);
+
+ // Try to detect the user choosing select-all
+ if (display.input.selectionStart != null) {
+ if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
+ var i = 0, poll = function() {
+ if (display.selForContextMenu == cm.doc.sel && display.input.selectionStart == 0)
+ operation(cm, commands.selectAll)(cm);
+ else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
+ else resetInput(cm);
+ };
+ display.detectingSelectAll = setTimeout(poll, 200);
+ }
+ }
+
+ if (ie && ie_version >= 9) prepareSelectAllHack();
+ if (captureRightClick) {
+ e_stop(e);
+ var mouseup = function() {
+ off(window, "mouseup", mouseup);
+ setTimeout(rehide, 20);
+ };
+ on(window, "mouseup", mouseup);
+ } else {
+ setTimeout(rehide, 50);
+ }
+ }
+
+ function contextMenuInGutter(cm, e) {
+ if (!hasHandler(cm, "gutterContextMenu")) return false;
+ return gutterEvent(cm, e, "gutterContextMenu", false, signal);
+ }
+
+ // UPDATING
+
+ // Compute the position of the end of a change (its 'to' property
+ // refers to the pre-change end).
+ var changeEnd = CodeMirror.changeEnd = function(change) {
+ if (!change.text) return change.to;
+ return Pos(change.from.line + change.text.length - 1,
+ lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
+ };
+
+ // Adjust a position to refer to the post-change position of the
+ // same text, or the end of the change if the change covers it.
+ function adjustForChange(pos, change) {
+ if (cmp(pos, change.from) < 0) return pos;
+ if (cmp(pos, change.to) <= 0) return changeEnd(change);
+
+ var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
+ if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
+ return Pos(line, ch);
+ }
+
+ function computeSelAfterChange(doc, change) {
+ var out = [];
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ var range = doc.sel.ranges[i];
+ out.push(new Range(adjustForChange(range.anchor, change),
+ adjustForChange(range.head, change)));
+ }
+ return normalizeSelection(out, doc.sel.primIndex);
+ }
+
+ function offsetPos(pos, old, nw) {
+ if (pos.line == old.line)
+ return Pos(nw.line, pos.ch - old.ch + nw.ch);
+ else
+ return Pos(nw.line + (pos.line - old.line), pos.ch);
+ }
+
+ // Used by replaceSelections to allow moving the selection to the
+ // start or around the replaced test. Hint may be "start" or "around".
+ function computeReplacedSel(doc, changes, hint) {
+ var out = [];
+ var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
+ for (var i = 0; i < changes.length; i++) {
+ var change = changes[i];
+ var from = offsetPos(change.from, oldPrev, newPrev);
+ var to = offsetPos(changeEnd(change), oldPrev, newPrev);
+ oldPrev = change.to;
+ newPrev = to;
+ if (hint == "around") {
+ var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
+ out[i] = new Range(inv ? to : from, inv ? from : to);
+ } else {
+ out[i] = new Range(from, from);
+ }
+ }
+ return new Selection(out, doc.sel.primIndex);
+ }
+
+ // Allow "beforeChange" event handlers to influence a change
+ function filterChange(doc, change, update) {
+ var obj = {
+ canceled: false,
+ from: change.from,
+ to: change.to,
+ text: change.text,
+ origin: change.origin,
+ cancel: function() { this.canceled = true; }
+ };
+ if (update) obj.update = function(from, to, text, origin) {
+ if (from) this.from = clipPos(doc, from);
+ if (to) this.to = clipPos(doc, to);
+ if (text) this.text = text;
+ if (origin !== undefined) this.origin = origin;
+ };
+ signal(doc, "beforeChange", doc, obj);
+ if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
+
+ if (obj.canceled) return null;
+ return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
+ }
+
+ // Apply a change to a document, and add it to the document's
+ // history, and propagating it to all linked documents.
+ function makeChange(doc, change, ignoreReadOnly) {
+ if (doc.cm) {
+ if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
+ if (doc.cm.state.suppressEdits) return;
+ }
+
+ if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
+ change = filterChange(doc, change, true);
+ if (!change) return;
+ }
+
+ // Possibly split or suppress the update based on the presence
+ // of read-only spans in its range.
+ var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
+ if (split) {
+ for (var i = split.length - 1; i >= 0; --i)
+ makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
+ } else {
+ makeChangeInner(doc, change);
+ }
+ }
+
+ function makeChangeInner(doc, change) {
+ if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
+ var selAfter = computeSelAfterChange(doc, change);
+ addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
+
+ makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
+ var rebased = [];
+
+ linkedDocs(doc, function(doc, sharedHist) {
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+ rebaseHist(doc.history, change);
+ rebased.push(doc.history);
+ }
+ makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
+ });
+ }
+
+ // Revert a change stored in a document's history.
+ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
+ if (doc.cm && doc.cm.state.suppressEdits) return;
+
+ var hist = doc.history, event, selAfter = doc.sel;
+ var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
+
+ // Verify that there is a useable event (so that ctrl-z won't
+ // needlessly clear selection events)
+ for (var i = 0; i < source.length; i++) {
+ event = source[i];
+ if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
+ break;
+ }
+ if (i == source.length) return;
+ hist.lastOrigin = hist.lastSelOrigin = null;
+
+ for (;;) {
+ event = source.pop();
+ if (event.ranges) {
+ pushSelectionToHistory(event, dest);
+ if (allowSelectionOnly && !event.equals(doc.sel)) {
+ setSelection(doc, event, {clearRedo: false});
+ return;
+ }
+ selAfter = event;
+ }
+ else break;
+ }
+
+ // Build up a reverse change object to add to the opposite history
+ // stack (redo when undoing, and vice versa).
+ var antiChanges = [];
+ pushSelectionToHistory(selAfter, dest);
+ dest.push({changes: antiChanges, generation: hist.generation});
+ hist.generation = event.generation || ++hist.maxGeneration;
+
+ var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
+
+ for (var i = event.changes.length - 1; i >= 0; --i) {
+ var change = event.changes[i];
+ change.origin = type;
+ if (filter && !filterChange(doc, change, false)) {
+ source.length = 0;
+ return;
+ }
+
+ antiChanges.push(historyChangeFromChange(doc, change));
+
+ var after = i ? computeSelAfterChange(doc, change) : lst(source);
+ makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
+ if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
+ var rebased = [];
+
+ // Propagate to the linked documents
+ linkedDocs(doc, function(doc, sharedHist) {
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+ rebaseHist(doc.history, change);
+ rebased.push(doc.history);
+ }
+ makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
+ });
+ }
+ }
+
+ // Sub-views need their line numbers shifted when text is added
+ // above or below them in the parent document.
+ function shiftDoc(doc, distance) {
+ if (distance == 0) return;
+ doc.first += distance;
+ doc.sel = new Selection(map(doc.sel.ranges, function(range) {
+ return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
+ Pos(range.head.line + distance, range.head.ch));
+ }), doc.sel.primIndex);
+ if (doc.cm) {
+ regChange(doc.cm, doc.first, doc.first - distance, distance);
+ for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
+ regLineChange(doc.cm, l, "gutter");
+ }
+ }
+
+ // More lower-level change function, handling only a single document
+ // (not linked ones).
+ function makeChangeSingleDoc(doc, change, selAfter, spans) {
+ if (doc.cm && !doc.cm.curOp)
+ return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
+
+ if (change.to.line < doc.first) {
+ shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
+ return;
+ }
+ if (change.from.line > doc.lastLine()) return;
+
+ // Clip the change to the size of this doc
+ if (change.from.line < doc.first) {
+ var shift = change.text.length - 1 - (doc.first - change.from.line);
+ shiftDoc(doc, shift);
+ change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
+ text: [lst(change.text)], origin: change.origin};
+ }
+ var last = doc.lastLine();
+ if (change.to.line > last) {
+ change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
+ text: [change.text[0]], origin: change.origin};
+ }
+
+ change.removed = getBetween(doc, change.from, change.to);
+
+ if (!selAfter) selAfter = computeSelAfterChange(doc, change);
+ if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
+ else updateDoc(doc, change, spans);
+ setSelectionNoUndo(doc, selAfter, sel_dontScroll);
+ }
+
+ // Handle the interaction of a change to a document with the editor
+ // that this document is part of.
+ function makeChangeSingleDocInEditor(cm, change, spans) {
+ var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
+
+ var recomputeMaxLength = false, checkWidthStart = from.line;
+ if (!cm.options.lineWrapping) {
+ checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
+ doc.iter(checkWidthStart, to.line + 1, function(line) {
+ if (line == display.maxLine) {
+ recomputeMaxLength = true;
+ return true;
+ }
+ });
+ }
+
+ if (doc.sel.contains(change.from, change.to) > -1)
+ signalCursorActivity(cm);
+
+ updateDoc(doc, change, spans, estimateHeight(cm));
+
+ if (!cm.options.lineWrapping) {
+ doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
+ var len = lineLength(line);
+ if (len > display.maxLineLength) {
+ display.maxLine = line;
+ display.maxLineLength = len;
+ display.maxLineChanged = true;
+ recomputeMaxLength = false;
+ }
+ });
+ if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
+ }
+
+ // Adjust frontier, schedule worker
+ doc.frontier = Math.min(doc.frontier, from.line);
+ startWorker(cm, 400);
+
+ var lendiff = change.text.length - (to.line - from.line) - 1;
+ // Remember that these lines changed, for updating the display
+ if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
+ regLineChange(cm, from.line, "text");
+ else
+ regChange(cm, from.line, to.line + 1, lendiff);
+
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
+ if (changeHandler || changesHandler) {
+ var obj = {
+ from: from, to: to,
+ text: change.text,
+ removed: change.removed,
+ origin: change.origin
+ };
+ if (changeHandler) signalLater(cm, "change", cm, obj);
+ if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
+ }
+ cm.display.selForContextMenu = null;
+ }
+
+ function replaceRange(doc, code, from, to, origin) {
+ if (!to) to = from;
+ if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
+ if (typeof code == "string") code = splitLines(code);
+ makeChange(doc, {from: from, to: to, text: code, origin: origin});
+ }
+
+ // SCROLLING THINGS INTO VIEW
+
+ // If an editor sits on the top or bottom of the window, partially
+ // scrolled out of view, this ensures that the cursor is visible.
+ function maybeScrollWindow(cm, coords) {
+ var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
+ if (coords.top + box.top < 0) doScroll = true;
+ else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
+ if (doScroll != null && !phantom) {
+ var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
+ (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
+ (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
+ coords.left + "px; width: 2px;");
+ cm.display.lineSpace.appendChild(scrollNode);
+ scrollNode.scrollIntoView(doScroll);
+ cm.display.lineSpace.removeChild(scrollNode);
+ }
+ }
+
+ // Scroll a given position into view (immediately), verifying that
+ // it actually became visible (as line heights are accurately
+ // measured, the position of something may 'drift' during drawing).
+ function scrollPosIntoView(cm, pos, end, margin) {
+ if (margin == null) margin = 0;
+ for (var limit = 0; limit < 5; limit++) {
+ var changed = false, coords = cursorCoords(cm, pos);
+ var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
+ var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
+ Math.min(coords.top, endCoords.top) - margin,
+ Math.max(coords.left, endCoords.left),
+ Math.max(coords.bottom, endCoords.bottom) + margin);
+ var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
+ if (scrollPos.scrollTop != null) {
+ setScrollTop(cm, scrollPos.scrollTop);
+ if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
+ }
+ if (scrollPos.scrollLeft != null) {
+ setScrollLeft(cm, scrollPos.scrollLeft);
+ if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
+ }
+ if (!changed) return coords;
+ }
+ }
+
+ // Scroll a given set of coordinates into view (immediately).
+ function scrollIntoView(cm, x1, y1, x2, y2) {
+ var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
+ if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
+ if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
+ }
+
+ // Calculate a new scroll position needed to scroll the given
+ // rectangle into view. Returns an object with scrollTop and
+ // scrollLeft properties. When these are undefined, the
+ // vertical/horizontal position does not need to be adjusted.
+ function calculateScrollPos(cm, x1, y1, x2, y2) {
+ var display = cm.display, snapMargin = textHeight(cm.display);
+ if (y1 < 0) y1 = 0;
+ var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
+ var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
+ if (y2 - y1 > screen) y2 = y1 + screen;
+ var docBottom = cm.doc.height + paddingVert(display);
+ var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
+ if (y1 < screentop) {
+ result.scrollTop = atTop ? 0 : y1;
+ } else if (y2 > screentop + screen) {
+ var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
+ if (newTop != screentop) result.scrollTop = newTop;
+ }
+
+ var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
+ var screenw = display.scroller.clientWidth - scrollerCutOff - display.gutters.offsetWidth;
+ var tooWide = x2 - x1 > screenw;
+ if (tooWide) x2 = x1 + screenw;
+ if (x1 < 10)
+ result.scrollLeft = 0;
+ else if (x1 < screenleft)
+ result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
+ else if (x2 > screenw + screenleft - 3)
+ result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
+
+ return result;
+ }
+
+ // Store a relative adjustment to the scroll position in the current
+ // operation (to be applied when the operation finishes).
+ function addToScrollPos(cm, left, top) {
+ if (left != null || top != null) resolveScrollToPos(cm);
+ if (left != null)
+ cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
+ if (top != null)
+ cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
+ }
+
+ // Make sure that at the end of the operation the current cursor is
+ // shown.
+ function ensureCursorVisible(cm) {
+ resolveScrollToPos(cm);
+ var cur = cm.getCursor(), from = cur, to = cur;
+ if (!cm.options.lineWrapping) {
+ from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
+ to = Pos(cur.line, cur.ch + 1);
+ }
+ cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
+ }
+
+ // When an operation has its scrollToPos property set, and another
+ // scroll action is applied before the end of the operation, this
+ // 'simulates' scrolling that position into view in a cheap way, so
+ // that the effect of intermediate scroll commands is not ignored.
+ function resolveScrollToPos(cm) {
+ var range = cm.curOp.scrollToPos;
+ if (range) {
+ cm.curOp.scrollToPos = null;
+ var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
+ var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
+ Math.min(from.top, to.top) - range.margin,
+ Math.max(from.right, to.right),
+ Math.max(from.bottom, to.bottom) + range.margin);
+ cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
+ }
+ }
+
+ // API UTILITIES
+
+ // Indent the given line. The how parameter can be "smart",
+ // "add"/null, "subtract", or "prev". When aggressive is false
+ // (typically set to true for forced single-line indents), empty
+ // lines are not indented, and places where the mode returns Pass
+ // are left alone.
+ function indentLine(cm, n, how, aggressive) {
+ var doc = cm.doc, state;
+ if (how == null) how = "add";
+ if (how == "smart") {
+ // Fall back to "prev" when the mode doesn't have an indentation
+ // method.
+ if (!doc.mode.indent) how = "prev";
+ else state = getStateBefore(cm, n);
+ }
+
+ var tabSize = cm.options.tabSize;
+ var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
+ if (line.stateAfter) line.stateAfter = null;
+ var curSpaceString = line.text.match(/^\s*/)[0], indentation;
+ if (!aggressive && !/\S/.test(line.text)) {
+ indentation = 0;
+ how = "not";
+ } else if (how == "smart") {
+ indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+ if (indentation == Pass || indentation > 150) {
+ if (!aggressive) return;
+ how = "prev";
+ }
+ }
+ if (how == "prev") {
+ if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
+ else indentation = 0;
+ } else if (how == "add") {
+ indentation = curSpace + cm.options.indentUnit;
+ } else if (how == "subtract") {
+ indentation = curSpace - cm.options.indentUnit;
+ } else if (typeof how == "number") {
+ indentation = curSpace + how;
+ }
+ indentation = Math.max(0, indentation);
+
+ var indentString = "", pos = 0;
+ if (cm.options.indentWithTabs)
+ for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
+ if (pos < indentation) indentString += spaceStr(indentation - pos);
+
+ if (indentString != curSpaceString) {
+ replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
+ } else {
+ // Ensure that, if the cursor was in the whitespace at the start
+ // of the line, it is moved to the end of that space.
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ var range = doc.sel.ranges[i];
+ if (range.head.line == n && range.head.ch < curSpaceString.length) {
+ var pos = Pos(n, curSpaceString.length);
+ replaceOneSelection(doc, i, new Range(pos, pos));
+ break;
+ }
+ }
+ }
+ line.stateAfter = null;
+ }
+
+ // Utility for applying a change to a line by handle or number,
+ // returning the number and optionally registering the line as
+ // changed.
+ function changeLine(doc, handle, changeType, op) {
+ var no = handle, line = handle;
+ if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
+ else no = lineNo(handle);
+ if (no == null) return null;
+ if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
+ return line;
+ }
+
+ // Helper for deleting text near the selection(s), used to implement
+ // backspace, delete, and similar functionality.
+ function deleteNearSelection(cm, compute) {
+ var ranges = cm.doc.sel.ranges, kill = [];
+ // Build up a set of ranges to kill first, merging overlapping
+ // ranges.
+ for (var i = 0; i < ranges.length; i++) {
+ var toKill = compute(ranges[i]);
+ while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
+ var replaced = kill.pop();
+ if (cmp(replaced.from, toKill.from) < 0) {
+ toKill.from = replaced.from;
+ break;
+ }
+ }
+ kill.push(toKill);
+ }
+ // Next, remove those actual ranges.
+ runInOp(cm, function() {
+ for (var i = kill.length - 1; i >= 0; i--)
+ replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
+ ensureCursorVisible(cm);
+ });
+ }
+
+ // Used for horizontal relative motion. Dir is -1 or 1 (left or
+ // right), unit can be "char", "column" (like char, but doesn't
+ // cross line boundaries), "word" (across next word), or "group" (to
+ // the start of next group of word or non-word-non-whitespace
+ // chars). The visually param controls whether, in right-to-left
+ // text, direction 1 means to move towards the next index in the
+ // string, or towards the character to the right of the current
+ // position. The resulting position will have a hitSide=true
+ // property if it reached the end of the document.
+ function findPosH(doc, pos, dir, unit, visually) {
+ var line = pos.line, ch = pos.ch, origDir = dir;
+ var lineObj = getLine(doc, line);
+ var possible = true;
+ function findNextLine() {
+ var l = line + dir;
+ if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
+ line = l;
+ return lineObj = getLine(doc, l);
+ }
+ function moveOnce(boundToLine) {
+ var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
+ if (next == null) {
+ if (!boundToLine && findNextLine()) {
+ if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
+ else ch = dir < 0 ? lineObj.text.length : 0;
+ } else return (possible = false);
+ } else ch = next;
+ return true;
+ }
+
+ if (unit == "char") moveOnce();
+ else if (unit == "column") moveOnce(true);
+ else if (unit == "word" || unit == "group") {
+ var sawType = null, group = unit == "group";
+ var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
+ for (var first = true;; first = false) {
+ if (dir < 0 && !moveOnce(!first)) break;
+ var cur = lineObj.text.charAt(ch) || "\n";
+ var type = isWordChar(cur, helper) ? "w"
+ : group && cur == "\n" ? "n"
+ : !group || /\s/.test(cur) ? null
+ : "p";
+ if (group && !first && !type) type = "s";
+ if (sawType && sawType != type) {
+ if (dir < 0) {dir = 1; moveOnce();}
+ break;
+ }
+
+ if (type) sawType = type;
+ if (dir > 0 && !moveOnce(!first)) break;
+ }
+ }
+ var result = skipAtomic(doc, Pos(line, ch), origDir, true);
+ if (!possible) result.hitSide = true;
+ return result;
+ }
+
+ // For relative vertical movement. Dir may be -1 or 1. Unit can be
+ // "page" or "line". The resulting position will have a hitSide=true
+ // property if it reached the end of the document.
+ function findPosV(cm, pos, dir, unit) {
+ var doc = cm.doc, x = pos.left, y;
+ if (unit == "page") {
+ var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+ y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
+ } else if (unit == "line") {
+ y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
+ }
+ for (;;) {
+ var target = coordsChar(cm, x, y);
+ if (!target.outside) break;
+ if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
+ y += dir * 5;
+ }
+ return target;
+ }
+
+ // EDITOR METHODS
+
+ // The publicly visible API. Note that methodOp(f) means
+ // 'wrap f in an operation, performed on its `this` parameter'.
+
+ // This is not the complete set of editor methods. Most of the
+ // methods defined on the Doc type are also injected into
+ // CodeMirror.prototype, for backwards compatibility and
+ // convenience.
+
+ CodeMirror.prototype = {
+ constructor: CodeMirror,
+ focus: function(){window.focus(); focusInput(this); fastPoll(this);},
+
+ setOption: function(option, value) {
+ var options = this.options, old = options[option];
+ if (options[option] == value && option != "mode") return;
+ options[option] = value;
+ if (optionHandlers.hasOwnProperty(option))
+ operation(this, optionHandlers[option])(this, value, old);
+ },
+
+ getOption: function(option) {return this.options[option];},
+ getDoc: function() {return this.doc;},
+
+ addKeyMap: function(map, bottom) {
+ this.state.keyMaps[bottom ? "push" : "unshift"](map);
+ },
+ removeKeyMap: function(map) {
+ var maps = this.state.keyMaps;
+ for (var i = 0; i < maps.length; ++i)
+ if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
+ maps.splice(i, 1);
+ return true;
+ }
+ },
+
+ addOverlay: methodOp(function(spec, options) {
+ var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
+ if (mode.startState) throw new Error("Overlays may not be stateful.");
+ this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
+ this.state.modeGen++;
+ regChange(this);
+ }),
+ removeOverlay: methodOp(function(spec) {
+ var overlays = this.state.overlays;
+ for (var i = 0; i < overlays.length; ++i) {
+ var cur = overlays[i].modeSpec;
+ if (cur == spec || typeof spec == "string" && cur.name == spec) {
+ overlays.splice(i, 1);
+ this.state.modeGen++;
+ regChange(this);
+ return;
+ }
+ }
+ }),
+
+ indentLine: methodOp(function(n, dir, aggressive) {
+ if (typeof dir != "string" && typeof dir != "number") {
+ if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
+ else dir = dir ? "add" : "subtract";
+ }
+ if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
+ }),
+ indentSelection: methodOp(function(how) {
+ var ranges = this.doc.sel.ranges, end = -1;
+ for (var i = 0; i < ranges.length; i++) {
+ var range = ranges[i];
+ if (!range.empty()) {
+ var from = range.from(), to = range.to();
+ var start = Math.max(end, from.line);
+ end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
+ for (var j = start; j < end; ++j)
+ indentLine(this, j, how);
+ var newRanges = this.doc.sel.ranges;
+ if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
+ replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
+ } else if (range.head.line > end) {
+ indentLine(this, range.head.line, how, true);
+ end = range.head.line;
+ if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
+ }
+ }
+ }),
+
+ // Fetch the parser token for a given character. Useful for hacks
+ // that want to inspect the mode state (say, for completion).
+ getTokenAt: function(pos, precise) {
+ var doc = this.doc;
+ pos = clipPos(doc, pos);
+ var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
+ var line = getLine(doc, pos.line);
+ var stream = new StringStream(line.text, this.options.tabSize);
+ while (stream.pos < pos.ch && !stream.eol()) {
+ stream.start = stream.pos;
+ var style = readToken(mode, stream, state);
+ }
+ return {start: stream.start,
+ end: stream.pos,
+ string: stream.current(),
+ type: style || null,
+ state: state};
+ },
+
+ getTokenTypeAt: function(pos) {
+ pos = clipPos(this.doc, pos);
+ var styles = getLineStyles(this, getLine(this.doc, pos.line));
+ var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
+ var type;
+ if (ch == 0) type = styles[2];
+ else for (;;) {
+ var mid = (before + after) >> 1;
+ if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
+ else if (styles[mid * 2 + 1] < ch) before = mid + 1;
+ else { type = styles[mid * 2 + 2]; break; }
+ }
+ var cut = type ? type.indexOf("cm-overlay ") : -1;
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
+ },
+
+ getModeAt: function(pos) {
+ var mode = this.doc.mode;
+ if (!mode.innerMode) return mode;
+ return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
+ },
+
+ getHelper: function(pos, type) {
+ return this.getHelpers(pos, type)[0];
+ },
+
+ getHelpers: function(pos, type) {
+ var found = [];
+ if (!helpers.hasOwnProperty(type)) return helpers;
+ var help = helpers[type], mode = this.getModeAt(pos);
+ if (typeof mode[type] == "string") {
+ if (help[mode[type]]) found.push(help[mode[type]]);
+ } else if (mode[type]) {
+ for (var i = 0; i < mode[type].length; i++) {
+ var val = help[mode[type][i]];
+ if (val) found.push(val);
+ }
+ } else if (mode.helperType && help[mode.helperType]) {
+ found.push(help[mode.helperType]);
+ } else if (help[mode.name]) {
+ found.push(help[mode.name]);
+ }
+ for (var i = 0; i < help._global.length; i++) {
+ var cur = help._global[i];
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
+ found.push(cur.val);
+ }
+ return found;
+ },
+
+ getStateAfter: function(line, precise) {
+ var doc = this.doc;
+ line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
+ return getStateBefore(this, line + 1, precise);
+ },
+
+ cursorCoords: function(start, mode) {
+ var pos, range = this.doc.sel.primary();
+ if (start == null) pos = range.head;
+ else if (typeof start == "object") pos = clipPos(this.doc, start);
+ else pos = start ? range.from() : range.to();
+ return cursorCoords(this, pos, mode || "page");
+ },
+
+ charCoords: function(pos, mode) {
+ return charCoords(this, clipPos(this.doc, pos), mode || "page");
+ },
+
+ coordsChar: function(coords, mode) {
+ coords = fromCoordSystem(this, coords, mode || "page");
+ return coordsChar(this, coords.left, coords.top);
+ },
+
+ lineAtHeight: function(height, mode) {
+ height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
+ return lineAtHeight(this.doc, height + this.display.viewOffset);
+ },
+ heightAtLine: function(line, mode) {
+ var end = false, last = this.doc.first + this.doc.size - 1;
+ if (line < this.doc.first) line = this.doc.first;
+ else if (line > last) { line = last; end = true; }
+ var lineObj = getLine(this.doc, line);
+ return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
+ (end ? this.doc.height - heightAtLine(lineObj) : 0);
+ },
+
+ defaultTextHeight: function() { return textHeight(this.display); },
+ defaultCharWidth: function() { return charWidth(this.display); },
+
+ setGutterMarker: methodOp(function(line, gutterID, value) {
+ return changeLine(this.doc, line, "gutter", function(line) {
+ var markers = line.gutterMarkers || (line.gutterMarkers = {});
+ markers[gutterID] = value;
+ if (!value && isEmpty(markers)) line.gutterMarkers = null;
+ return true;
+ });
+ }),
+
+ clearGutter: methodOp(function(gutterID) {
+ var cm = this, doc = cm.doc, i = doc.first;
+ doc.iter(function(line) {
+ if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
+ line.gutterMarkers[gutterID] = null;
+ regLineChange(cm, i, "gutter");
+ if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
+ }
+ ++i;
+ });
+ }),
+
+ addLineWidget: methodOp(function(handle, node, options) {
+ return addLineWidget(this, handle, node, options);
+ }),
+
+ removeLineWidget: function(widget) { widget.clear(); },
+
+ lineInfo: function(line) {
+ if (typeof line == "number") {
+ if (!isLine(this.doc, line)) return null;
+ var n = line;
+ line = getLine(this.doc, line);
+ if (!line) return null;
+ } else {
+ var n = lineNo(line);
+ if (n == null) return null;
+ }
+ return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
+ textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
+ widgets: line.widgets};
+ },
+
+ getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
+
+ addWidget: function(pos, node, scroll, vert, horiz) {
+ var display = this.display;
+ pos = cursorCoords(this, clipPos(this.doc, pos));
+ var top = pos.bottom, left = pos.left;
+ node.style.position = "absolute";
+ display.sizer.appendChild(node);
+ if (vert == "over") {
+ top = pos.top;
+ } else if (vert == "above" || vert == "near") {
+ var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
+ hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
+ // Default to positioning above (if specified and possible); otherwise default to positioning below
+ if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
+ top = pos.top - node.offsetHeight;
+ else if (pos.bottom + node.offsetHeight <= vspace)
+ top = pos.bottom;
+ if (left + node.offsetWidth > hspace)
+ left = hspace - node.offsetWidth;
+ }
+ node.style.top = top + "px";
+ node.style.left = node.style.right = "";
+ if (horiz == "right") {
+ left = display.sizer.clientWidth - node.offsetWidth;
+ node.style.right = "0px";
+ } else {
+ if (horiz == "left") left = 0;
+ else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
+ node.style.left = left + "px";
+ }
+ if (scroll)
+ scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
+ },
+
+ triggerOnKeyDown: methodOp(onKeyDown),
+ triggerOnKeyPress: methodOp(onKeyPress),
+ triggerOnKeyUp: onKeyUp,
+
+ execCommand: function(cmd) {
+ if (commands.hasOwnProperty(cmd))
+ return commands[cmd](this);
+ },
+
+ findPosH: function(from, amount, unit, visually) {
+ var dir = 1;
+ if (amount < 0) { dir = -1; amount = -amount; }
+ for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
+ cur = findPosH(this.doc, cur, dir, unit, visually);
+ if (cur.hitSide) break;
+ }
+ return cur;
+ },
+
+ moveH: methodOp(function(dir, unit) {
+ var cm = this;
+ cm.extendSelectionsBy(function(range) {
+ if (cm.display.shift || cm.doc.extend || range.empty())
+ return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
+ else
+ return dir < 0 ? range.from() : range.to();
+ }, sel_move);
+ }),
+
+ deleteH: methodOp(function(dir, unit) {
+ var sel = this.doc.sel, doc = this.doc;
+ if (sel.somethingSelected())
+ doc.replaceSelection("", null, "+delete");
+ else
+ deleteNearSelection(this, function(range) {
+ var other = findPosH(doc, range.head, dir, unit, false);
+ return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
+ });
+ }),
+
+ findPosV: function(from, amount, unit, goalColumn) {
+ var dir = 1, x = goalColumn;
+ if (amount < 0) { dir = -1; amount = -amount; }
+ for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
+ var coords = cursorCoords(this, cur, "div");
+ if (x == null) x = coords.left;
+ else coords.left = x;
+ cur = findPosV(this, coords, dir, unit);
+ if (cur.hitSide) break;
+ }
+ return cur;
+ },
+
+ moveV: methodOp(function(dir, unit) {
+ var cm = this, doc = this.doc, goals = [];
+ var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
+ doc.extendSelectionsBy(function(range) {
+ if (collapse)
+ return dir < 0 ? range.from() : range.to();
+ var headPos = cursorCoords(cm, range.head, "div");
+ if (range.goalColumn != null) headPos.left = range.goalColumn;
+ goals.push(headPos.left);
+ var pos = findPosV(cm, headPos, dir, unit);
+ if (unit == "page" && range == doc.sel.primary())
+ addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
+ return pos;
+ }, sel_move);
+ if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
+ doc.sel.ranges[i].goalColumn = goals[i];
+ }),
+
+ // Find the word at the given position (as returned by coordsChar).
+ findWordAt: function(pos) {
+ var doc = this.doc, line = getLine(doc, pos.line).text;
+ var start = pos.ch, end = pos.ch;
+ if (line) {
+ var helper = this.getHelper(pos, "wordChars");
+ if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
+ var startChar = line.charAt(start);
+ var check = isWordChar(startChar, helper)
+ ? function(ch) { return isWordChar(ch, helper); }
+ : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
+ : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
+ while (start > 0 && check(line.charAt(start - 1))) --start;
+ while (end < line.length && check(line.charAt(end))) ++end;
+ }
+ return new Range(Pos(pos.line, start), Pos(pos.line, end));
+ },
+
+ toggleOverwrite: function(value) {
+ if (value != null && value == this.state.overwrite) return;
+ if (this.state.overwrite = !this.state.overwrite)
+ addClass(this.display.cursorDiv, "CodeMirror-overwrite");
+ else
+ rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
+
+ signal(this, "overwriteToggle", this, this.state.overwrite);
+ },
+ hasFocus: function() { return activeElt() == this.display.input; },
+
+ scrollTo: methodOp(function(x, y) {
+ if (x != null || y != null) resolveScrollToPos(this);
+ if (x != null) this.curOp.scrollLeft = x;
+ if (y != null) this.curOp.scrollTop = y;
+ }),
+ getScrollInfo: function() {
+ var scroller = this.display.scroller, co = scrollerCutOff;
+ return {left: scroller.scrollLeft, top: scroller.scrollTop,
+ height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
+ clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
+ },
+
+ scrollIntoView: methodOp(function(range, margin) {
+ if (range == null) {
+ range = {from: this.doc.sel.primary().head, to: null};
+ if (margin == null) margin = this.options.cursorScrollMargin;
+ } else if (typeof range == "number") {
+ range = {from: Pos(range, 0), to: null};
+ } else if (range.from == null) {
+ range = {from: range, to: null};
+ }
+ if (!range.to) range.to = range.from;
+ range.margin = margin || 0;
+
+ if (range.from.line != null) {
+ resolveScrollToPos(this);
+ this.curOp.scrollToPos = range;
+ } else {
+ var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
+ Math.min(range.from.top, range.to.top) - range.margin,
+ Math.max(range.from.right, range.to.right),
+ Math.max(range.from.bottom, range.to.bottom) + range.margin);
+ this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
+ }
+ }),
+
+ setSize: methodOp(function(width, height) {
+ var cm = this;
+ function interpret(val) {
+ return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
+ }
+ if (width != null) cm.display.wrapper.style.width = interpret(width);
+ if (height != null) cm.display.wrapper.style.height = interpret(height);
+ if (cm.options.lineWrapping) clearLineMeasurementCache(this);
+ var lineNo = cm.display.viewFrom;
+ cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
+ if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
+ if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
+ ++lineNo;
+ });
+ cm.curOp.forceUpdate = true;
+ signal(cm, "refresh", this);
+ }),
+
+ operation: function(f){return runInOp(this, f);},
+
+ refresh: methodOp(function() {
+ var oldHeight = this.display.cachedTextHeight;
+ regChange(this);
+ this.curOp.forceUpdate = true;
+ clearCaches(this);
+ this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
+ updateGutterSpace(this);
+ if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
+ estimateLineHeights(this);
+ signal(this, "refresh", this);
+ }),
+
+ swapDoc: methodOp(function(doc) {
+ var old = this.doc;
+ old.cm = null;
+ attachDoc(this, doc);
+ clearCaches(this);
+ resetInput(this);
+ this.scrollTo(doc.scrollLeft, doc.scrollTop);
+ this.curOp.forceScroll = true;
+ signalLater(this, "swapDoc", this, old);
+ return old;
+ }),
+
+ getInputField: function(){return this.display.input;},
+ getWrapperElement: function(){return this.display.wrapper;},
+ getScrollerElement: function(){return this.display.scroller;},
+ getGutterElement: function(){return this.display.gutters;}
+ };
+ eventMixin(CodeMirror);
+
+ // OPTION DEFAULTS
+
+ // The default configuration options.
+ var defaults = CodeMirror.defaults = {};
+ // Functions to run when options are changed.
+ var optionHandlers = CodeMirror.optionHandlers = {};
+
+ function option(name, deflt, handle, notOnInit) {
+ CodeMirror.defaults[name] = deflt;
+ if (handle) optionHandlers[name] =
+ notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
+ }
+
+ // Passed to option handlers when there is no old value.
+ var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
+
+ // These two are, on init, called from the constructor because they
+ // have to be initialized before the editor can start at all.
+ option("value", "", function(cm, val) {
+ cm.setValue(val);
+ }, true);
+ option("mode", null, function(cm, val) {
+ cm.doc.modeOption = val;
+ loadMode(cm);
+ }, true);
+
+ option("indentUnit", 2, loadMode, true);
+ option("indentWithTabs", false);
+ option("smartIndent", true);
+ option("tabSize", 4, function(cm) {
+ resetModeState(cm);
+ clearCaches(cm);
+ regChange(cm);
+ }, true);
+ option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val) {
+ cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
+ cm.refresh();
+ }, true);
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
+ option("electricChars", true);
+ option("rtlMoveVisually", !windows);
+ option("wholeLineUpdateBefore", true);
+
+ option("theme", "default", function(cm) {
+ themeChanged(cm);
+ guttersChanged(cm);
+ }, true);
+ option("keyMap", "default", keyMapChanged);
+ option("extraKeys", null);
+
+ option("lineWrapping", false, wrappingChanged, true);
+ option("gutters", [], function(cm) {
+ setGuttersForLineNumbers(cm.options);
+ guttersChanged(cm);
+ }, true);
+ option("fixedGutter", true, function(cm, val) {
+ cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
+ cm.refresh();
+ }, true);
+ option("coverGutterNextToScrollbar", false, updateScrollbars, true);
+ option("lineNumbers", false, function(cm) {
+ setGuttersForLineNumbers(cm.options);
+ guttersChanged(cm);
+ }, true);
+ option("firstLineNumber", 1, guttersChanged, true);
+ option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
+ option("showCursorWhenSelecting", false, updateSelection, true);
+
+ option("resetSelectionOnContextMenu", true);
+
+ option("readOnly", false, function(cm, val) {
+ if (val == "nocursor") {
+ onBlur(cm);
+ cm.display.input.blur();
+ cm.display.disabled = true;
+ } else {
+ cm.display.disabled = false;
+ if (!val) resetInput(cm);
+ }
+ });
+ option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, true);
+ option("dragDrop", true);
+
+ option("cursorBlinkRate", 530);
+ option("cursorScrollMargin", 0);
+ option("cursorHeight", 1, updateSelection, true);
+ option("singleCursorHeightPerLine", true, updateSelection, true);
+ option("workTime", 100);
+ option("workDelay", 100);
+ option("flattenSpans", true, resetModeState, true);
+ option("addModeClass", false, resetModeState, true);
+ option("pollInterval", 100);
+ option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
+ option("historyEventDelay", 1250);
+ option("viewportMargin", 10, function(cm){cm.refresh();}, true);
+ option("maxHighlightLength", 10000, resetModeState, true);
+ option("moveInputWithCursor", true, function(cm, val) {
+ if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
+ });
+
+ option("tabindex", null, function(cm, val) {
+ cm.display.input.tabIndex = val || "";
+ });
+ option("autofocus", null);
+
+ // MODE DEFINITION AND QUERYING
+
+ // Known modes, by name and by MIME
+ var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
+
+ // Extra arguments are stored as the mode's dependencies, which is
+ // used by (legacy) mechanisms like loadmode.js to automatically
+ // load a mode. (Preferred mechanism is the require/define calls.)
+ CodeMirror.defineMode = function(name, mode) {
+ if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
+ if (arguments.length > 2)
+ mode.dependencies = Array.prototype.slice.call(arguments, 2);
+ modes[name] = mode;
+ };
+
+ CodeMirror.defineMIME = function(mime, spec) {
+ mimeModes[mime] = spec;
+ };
+
+ // Given a MIME type, a {name, ...options} config object, or a name
+ // string, return a mode config object.
+ CodeMirror.resolveMode = function(spec) {
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
+ spec = mimeModes[spec];
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+ var found = mimeModes[spec.name];
+ if (typeof found == "string") found = {name: found};
+ spec = createObj(found, spec);
+ spec.name = found.name;
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
+ return CodeMirror.resolveMode("application/xml");
+ }
+ if (typeof spec == "string") return {name: spec};
+ else return spec || {name: "null"};
+ };
+
+ // Given a mode spec (anything that resolveMode accepts), find and
+ // initialize an actual mode object.
+ CodeMirror.getMode = function(options, spec) {
+ var spec = CodeMirror.resolveMode(spec);
+ var mfactory = modes[spec.name];
+ if (!mfactory) return CodeMirror.getMode(options, "text/plain");
+ var modeObj = mfactory(options, spec);
+ if (modeExtensions.hasOwnProperty(spec.name)) {
+ var exts = modeExtensions[spec.name];
+ for (var prop in exts) {
+ if (!exts.hasOwnProperty(prop)) continue;
+ if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
+ modeObj[prop] = exts[prop];
+ }
+ }
+ modeObj.name = spec.name;
+ if (spec.helperType) modeObj.helperType = spec.helperType;
+ if (spec.modeProps) for (var prop in spec.modeProps)
+ modeObj[prop] = spec.modeProps[prop];
+
+ return modeObj;
+ };
+
+ // Minimal default mode.
+ CodeMirror.defineMode("null", function() {
+ return {token: function(stream) {stream.skipToEnd();}};
+ });
+ CodeMirror.defineMIME("text/plain", "null");
+
+ // This can be used to attach properties to mode objects from
+ // outside the actual mode definition.
+ var modeExtensions = CodeMirror.modeExtensions = {};
+ CodeMirror.extendMode = function(mode, properties) {
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
+ copyObj(properties, exts);
+ };
+
+ // EXTENSIONS
+
+ CodeMirror.defineExtension = function(name, func) {
+ CodeMirror.prototype[name] = func;
+ };
+ CodeMirror.defineDocExtension = function(name, func) {
+ Doc.prototype[name] = func;
+ };
+ CodeMirror.defineOption = option;
+
+ var initHooks = [];
+ CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
+
+ var helpers = CodeMirror.helpers = {};
+ CodeMirror.registerHelper = function(type, name, value) {
+ if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
+ helpers[type][name] = value;
+ };
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
+ CodeMirror.registerHelper(type, name, value);
+ helpers[type]._global.push({pred: predicate, val: value});
+ };
+
+ // MODE STATE HANDLING
+
+ // Utility functions for working with state. Exported because nested
+ // modes need to do this for their inner modes.
+
+ var copyState = CodeMirror.copyState = function(mode, state) {
+ if (state === true) return state;
+ if (mode.copyState) return mode.copyState(state);
+ var nstate = {};
+ for (var n in state) {
+ var val = state[n];
+ if (val instanceof Array) val = val.concat([]);
+ nstate[n] = val;
+ }
+ return nstate;
+ };
+
+ var startState = CodeMirror.startState = function(mode, a1, a2) {
+ return mode.startState ? mode.startState(a1, a2) : true;
+ };
+
+ // Given a mode and a state (for that mode), find the inner mode and
+ // state at the position that the state refers to.
+ CodeMirror.innerMode = function(mode, state) {
+ while (mode.innerMode) {
+ var info = mode.innerMode(state);
+ if (!info || info.mode == mode) break;
+ state = info.state;
+ mode = info.mode;
+ }
+ return info || {mode: mode, state: state};
+ };
+
+ // STANDARD COMMANDS
+
+ // Commands are parameter-less actions that can be performed on an
+ // editor, mostly used for keybindings.
+ var commands = CodeMirror.commands = {
+ selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
+ singleSelection: function(cm) {
+ cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
+ },
+ killLine: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ if (range.empty()) {
+ var len = getLine(cm.doc, range.head.line).text.length;
+ if (range.head.ch == len && range.head.line < cm.lastLine())
+ return {from: range.head, to: Pos(range.head.line + 1, 0)};
+ else
+ return {from: range.head, to: Pos(range.head.line, len)};
+ } else {
+ return {from: range.from(), to: range.to()};
+ }
+ });
+ },
+ deleteLine: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ return {from: Pos(range.from().line, 0),
+ to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
+ });
+ },
+ delLineLeft: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ return {from: Pos(range.from().line, 0), to: range.from()};
+ });
+ },
+ delWrappedLineLeft: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var leftPos = cm.coordsChar({left: 0, top: top}, "div");
+ return {from: leftPos, to: range.from()};
+ });
+ },
+ delWrappedLineRight: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+ return {from: range.from(), to: rightPos };
+ });
+ },
+ undo: function(cm) {cm.undo();},
+ redo: function(cm) {cm.redo();},
+ undoSelection: function(cm) {cm.undoSelection();},
+ redoSelection: function(cm) {cm.redoSelection();},
+ goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
+ goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
+ goLineStart: function(cm) {
+ cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
+ {origin: "+move", bias: 1});
+ },
+ goLineStartSmart: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ return lineStartSmart(cm, range.head);
+ }, {origin: "+move", bias: 1});
+ },
+ goLineEnd: function(cm) {
+ cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
+ {origin: "+move", bias: -1});
+ },
+ goLineRight: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+ }, sel_move);
+ },
+ goLineLeft: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ return cm.coordsChar({left: 0, top: top}, "div");
+ }, sel_move);
+ },
+ goLineLeftSmart: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var pos = cm.coordsChar({left: 0, top: top}, "div");
+ if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
+ return pos;
+ }, sel_move);
+ },
+ goLineUp: function(cm) {cm.moveV(-1, "line");},
+ goLineDown: function(cm) {cm.moveV(1, "line");},
+ goPageUp: function(cm) {cm.moveV(-1, "page");},
+ goPageDown: function(cm) {cm.moveV(1, "page");},
+ goCharLeft: function(cm) {cm.moveH(-1, "char");},
+ goCharRight: function(cm) {cm.moveH(1, "char");},
+ goColumnLeft: function(cm) {cm.moveH(-1, "column");},
+ goColumnRight: function(cm) {cm.moveH(1, "column");},
+ goWordLeft: function(cm) {cm.moveH(-1, "word");},
+ goGroupRight: function(cm) {cm.moveH(1, "group");},
+ goGroupLeft: function(cm) {cm.moveH(-1, "group");},
+ goWordRight: function(cm) {cm.moveH(1, "word");},
+ delCharBefore: function(cm) {cm.deleteH(-1, "char");},
+ delCharAfter: function(cm) {cm.deleteH(1, "char");},
+ delWordBefore: function(cm) {cm.deleteH(-1, "word");},
+ delWordAfter: function(cm) {cm.deleteH(1, "word");},
+ delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
+ delGroupAfter: function(cm) {cm.deleteH(1, "group");},
+ indentAuto: function(cm) {cm.indentSelection("smart");},
+ indentMore: function(cm) {cm.indentSelection("add");},
+ indentLess: function(cm) {cm.indentSelection("subtract");},
+ insertTab: function(cm) {cm.replaceSelection("\t");},
+ insertSoftTab: function(cm) {
+ var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
+ for (var i = 0; i < ranges.length; i++) {
+ var pos = ranges[i].from();
+ var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
+ spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
+ }
+ cm.replaceSelections(spaces);
+ },
+ defaultTab: function(cm) {
+ if (cm.somethingSelected()) cm.indentSelection("add");
+ else cm.execCommand("insertTab");
+ },
+ transposeChars: function(cm) {
+ runInOp(cm, function() {
+ var ranges = cm.listSelections(), newSel = [];
+ for (var i = 0; i < ranges.length; i++) {
+ var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
+ if (line) {
+ if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
+ if (cur.ch > 0) {
+ cur = new Pos(cur.line, cur.ch + 1);
+ cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
+ Pos(cur.line, cur.ch - 2), cur, "+transpose");
+ } else if (cur.line > cm.doc.first) {
+ var prev = getLine(cm.doc, cur.line - 1).text;
+ if (prev)
+ cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
+ Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
+ }
+ }
+ newSel.push(new Range(cur, cur));
+ }
+ cm.setSelections(newSel);
+ });
+ },
+ newlineAndIndent: function(cm) {
+ runInOp(cm, function() {
+ var len = cm.listSelections().length;
+ for (var i = 0; i < len; i++) {
+ var range = cm.listSelections()[i];
+ cm.replaceRange("\n", range.anchor, range.head, "+input");
+ cm.indentLine(range.from().line + 1, null, true);
+ ensureCursorVisible(cm);
+ }
+ });
+ },
+ toggleOverwrite: function(cm) {cm.toggleOverwrite();}
+ };
+
+ // STANDARD KEYMAPS
+
+ var keyMap = CodeMirror.keyMap = {};
+ keyMap.basic = {
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
+ "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
+ "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
+ "Esc": "singleSelection"
+ };
+ // Note that the save and find-related commands aren't defined by
+ // default. User code or addons can define them. Unknown commands
+ // are simply ignored.
+ keyMap.pcDefault = {
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
+ "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
+ "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
+ "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
+ "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
+ fallthrough: "basic"
+ };
+ keyMap.macDefault = {
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
+ "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
+ "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
+ "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
+ "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
+ fallthrough: ["basic", "emacsy"]
+ };
+ // Very basic readline/emacs-style bindings, which are standard on Mac.
+ keyMap.emacsy = {
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+ "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
+ "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
+ };
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
+
+ // KEYMAP DISPATCH
+
+ function getKeyMap(val) {
+ if (typeof val == "string") return keyMap[val];
+ else return val;
+ }
+
+ // Given an array of keymaps and a key name, call handle on any
+ // bindings found, until that returns a truthy value, at which point
+ // we consider the key handled. Implements things like binding a key
+ // to false stopping further handling and keymap fallthrough.
+ var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) {
+ function lookup(map) {
+ map = getKeyMap(map);
+ var found = map[name];
+ if (found === false) return "stop";
+ if (found != null && handle(found)) return true;
+ if (map.nofallthrough) return "stop";
+
+ var fallthrough = map.fallthrough;
+ if (fallthrough == null) return false;
+ if (Object.prototype.toString.call(fallthrough) != "[object Array]")
+ return lookup(fallthrough);
+ for (var i = 0; i < fallthrough.length; ++i) {
+ var done = lookup(fallthrough[i]);
+ if (done) return done;
+ }
+ return false;
+ }
+
+ for (var i = 0; i < maps.length; ++i) {
+ var done = lookup(maps[i]);
+ if (done) return done != "stop";
+ }
+ };
+
+ // Modifier key presses don't count as 'real' key presses for the
+ // purpose of keymap fallthrough.
+ var isModifierKey = CodeMirror.isModifierKey = function(event) {
+ var name = keyNames[event.keyCode];
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
+ };
+
+ // Look up the name of a key as indicated by an event object.
+ var keyName = CodeMirror.keyName = function(event, noShift) {
+ if (presto && event.keyCode == 34 && event["char"]) return false;
+ var name = keyNames[event.keyCode];
+ if (name == null || event.altGraphKey) return false;
+ if (event.altKey) name = "Alt-" + name;
+ if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
+ if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name;
+ if (!noShift && event.shiftKey) name = "Shift-" + name;
+ return name;
+ };
+
+ // FROMTEXTAREA
+
+ CodeMirror.fromTextArea = function(textarea, options) {
+ if (!options) options = {};
+ options.value = textarea.value;
+ if (!options.tabindex && textarea.tabindex)
+ options.tabindex = textarea.tabindex;
+ if (!options.placeholder && textarea.placeholder)
+ options.placeholder = textarea.placeholder;
+ // Set autofocus to true if this textarea is focused, or if it has
+ // autofocus and no other element is focused.
+ if (options.autofocus == null) {
+ var hasFocus = activeElt();
+ options.autofocus = hasFocus == textarea ||
+ textarea.getAttribute("autofocus") != null && hasFocus == document.body;
+ }
+
+ function save() {textarea.value = cm.getValue();}
+ if (textarea.form) {
+ on(textarea.form, "submit", save);
+ // Deplorable hack to make the submit method do the right thing.
+ if (!options.leaveSubmitMethodAlone) {
+ var form = textarea.form, realSubmit = form.submit;
+ try {
+ var wrappedSubmit = form.submit = function() {
+ save();
+ form.submit = realSubmit;
+ form.submit();
+ form.submit = wrappedSubmit;
+ };
+ } catch(e) {}
+ }
+ }
+
+ textarea.style.display = "none";
+ var cm = CodeMirror(function(node) {
+ textarea.parentNode.insertBefore(node, textarea.nextSibling);
+ }, options);
+ cm.save = save;
+ cm.getTextArea = function() { return textarea; };
+ cm.toTextArea = function() {
+ cm.toTextArea = isNaN; // Prevent this from being ran twice
+ save();
+ textarea.parentNode.removeChild(cm.getWrapperElement());
+ textarea.style.display = "";
+ if (textarea.form) {
+ off(textarea.form, "submit", save);
+ if (typeof textarea.form.submit == "function")
+ textarea.form.submit = realSubmit;
+ }
+ };
+ return cm;
+ };
+
+ // STRING STREAM
+
+ // Fed to the mode parsers, provides helper functions to make
+ // parsers more succinct.
+
+ var StringStream = CodeMirror.StringStream = function(string, tabSize) {
+ this.pos = this.start = 0;
+ this.string = string;
+ this.tabSize = tabSize || 8;
+ this.lastColumnPos = this.lastColumnValue = 0;
+ this.lineStart = 0;
+ };
+
+ StringStream.prototype = {
+ eol: function() {return this.pos >= this.string.length;},
+ sol: function() {return this.pos == this.lineStart;},
+ peek: function() {return this.string.charAt(this.pos) || undefined;},
+ next: function() {
+ if (this.pos < this.string.length)
+ return this.string.charAt(this.pos++);
+ },
+ eat: function(match) {
+ var ch = this.string.charAt(this.pos);
+ if (typeof match == "string") var ok = ch == match;
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
+ if (ok) {++this.pos; return ch;}
+ },
+ eatWhile: function(match) {
+ var start = this.pos;
+ while (this.eat(match)){}
+ return this.pos > start;
+ },
+ eatSpace: function() {
+ var start = this.pos;
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
+ return this.pos > start;
+ },
+ skipToEnd: function() {this.pos = this.string.length;},
+ skipTo: function(ch) {
+ var found = this.string.indexOf(ch, this.pos);
+ if (found > -1) {this.pos = found; return true;}
+ },
+ backUp: function(n) {this.pos -= n;},
+ column: function() {
+ if (this.lastColumnPos < this.start) {
+ this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
+ this.lastColumnPos = this.start;
+ }
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+ },
+ indentation: function() {
+ return countColumn(this.string, null, this.tabSize) -
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+ },
+ match: function(pattern, consume, caseInsensitive) {
+ if (typeof pattern == "string") {
+ var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
+ var substr = this.string.substr(this.pos, pattern.length);
+ if (cased(substr) == cased(pattern)) {
+ if (consume !== false) this.pos += pattern.length;
+ return true;
+ }
+ } else {
+ var match = this.string.slice(this.pos).match(pattern);
+ if (match && match.index > 0) return null;
+ if (match && consume !== false) this.pos += match[0].length;
+ return match;
+ }
+ },
+ current: function(){return this.string.slice(this.start, this.pos);},
+ hideFirstChars: function(n, inner) {
+ this.lineStart += n;
+ try { return inner(); }
+ finally { this.lineStart -= n; }
+ }
+ };
+
+ // TEXTMARKERS
+
+ // Created with markText and setBookmark methods. A TextMarker is a
+ // handle that can be used to clear or find a marked position in the
+ // document. Line objects hold arrays (markedSpans) containing
+ // {from, to, marker} object pointing to such marker objects, and
+ // indicating that such a marker is present on that line. Multiple
+ // lines may point to the same marker when it spans across lines.
+ // The spans will have null for their from/to properties when the
+ // marker continues beyond the start/end of the line. Markers have
+ // links back to the lines they currently touch.
+
+ var TextMarker = CodeMirror.TextMarker = function(doc, type) {
+ this.lines = [];
+ this.type = type;
+ this.doc = doc;
+ };
+ eventMixin(TextMarker);
+
+ // Clear the marker.
+ TextMarker.prototype.clear = function() {
+ if (this.explicitlyCleared) return;
+ var cm = this.doc.cm, withOp = cm && !cm.curOp;
+ if (withOp) startOperation(cm);
+ if (hasHandler(this, "clear")) {
+ var found = this.find();
+ if (found) signalLater(this, "clear", found.from, found.to);
+ }
+ var min = null, max = null;
+ for (var i = 0; i < this.lines.length; ++i) {
+ var line = this.lines[i];
+ var span = getMarkedSpanFor(line.markedSpans, this);
+ if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
+ else if (cm) {
+ if (span.to != null) max = lineNo(line);
+ if (span.from != null) min = lineNo(line);
+ }
+ line.markedSpans = removeMarkedSpan(line.markedSpans, span);
+ if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
+ updateLineHeight(line, textHeight(cm.display));
+ }
+ if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
+ var visual = visualLine(this.lines[i]), len = lineLength(visual);
+ if (len > cm.display.maxLineLength) {
+ cm.display.maxLine = visual;
+ cm.display.maxLineLength = len;
+ cm.display.maxLineChanged = true;
+ }
+ }
+
+ if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
+ this.lines.length = 0;
+ this.explicitlyCleared = true;
+ if (this.atomic && this.doc.cantEdit) {
+ this.doc.cantEdit = false;
+ if (cm) reCheckSelection(cm.doc);
+ }
+ if (cm) signalLater(cm, "markerCleared", cm, this);
+ if (withOp) endOperation(cm);
+ if (this.parent) this.parent.clear();
+ };
+
+ // Find the position of the marker in the document. Returns a {from,
+ // to} object by default. Side can be passed to get a specific side
+ // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
+ // Pos objects returned contain a line object, rather than a line
+ // number (used to prevent looking up the same line twice).
+ TextMarker.prototype.find = function(side, lineObj) {
+ if (side == null && this.type == "bookmark") side = 1;
+ var from, to;
+ for (var i = 0; i < this.lines.length; ++i) {
+ var line = this.lines[i];
+ var span = getMarkedSpanFor(line.markedSpans, this);
+ if (span.from != null) {
+ from = Pos(lineObj ? line : lineNo(line), span.from);
+ if (side == -1) return from;
+ }
+ if (span.to != null) {
+ to = Pos(lineObj ? line : lineNo(line), span.to);
+ if (side == 1) return to;
+ }
+ }
+ return from && {from: from, to: to};
+ };
+
+ // Signals that the marker's widget changed, and surrounding layout
+ // should be recomputed.
+ TextMarker.prototype.changed = function() {
+ var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
+ if (!pos || !cm) return;
+ runInOp(cm, function() {
+ var line = pos.line, lineN = lineNo(pos.line);
+ var view = findViewForLine(cm, lineN);
+ if (view) {
+ clearLineMeasurementCacheFor(view);
+ cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
+ }
+ cm.curOp.updateMaxLine = true;
+ if (!lineIsHidden(widget.doc, line) && widget.height != null) {
+ var oldHeight = widget.height;
+ widget.height = null;
+ var dHeight = widgetHeight(widget) - oldHeight;
+ if (dHeight)
+ updateLineHeight(line, line.height + dHeight);
+ }
+ });
+ };
+
+ TextMarker.prototype.attachLine = function(line) {
+ if (!this.lines.length && this.doc.cm) {
+ var op = this.doc.cm.curOp;
+ if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
+ (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
+ }
+ this.lines.push(line);
+ };
+ TextMarker.prototype.detachLine = function(line) {
+ this.lines.splice(indexOf(this.lines, line), 1);
+ if (!this.lines.length && this.doc.cm) {
+ var op = this.doc.cm.curOp;
+ (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
+ }
+ };
+
+ // Collapsed markers have unique ids, in order to be able to order
+ // them, which is needed for uniquely determining an outer marker
+ // when they overlap (they may nest, but not partially overlap).
+ var nextMarkerId = 0;
+
+ // Create a marker, wire it up to the right lines, and
+ function markText(doc, from, to, options, type) {
+ // Shared markers (across linked documents) are handled separately
+ // (markTextShared will call out to this again, once per
+ // document).
+ if (options && options.shared) return markTextShared(doc, from, to, options, type);
+ // Ensure we are in an operation.
+ if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
+
+ var marker = new TextMarker(doc, type), diff = cmp(from, to);
+ if (options) copyObj(options, marker, false);
+ // Don't connect empty markers unless clearWhenEmpty is false
+ if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
+ return marker;
+ if (marker.replacedWith) {
+ // Showing up as a widget implies collapsed (widget replaces text)
+ marker.collapsed = true;
+ marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
+ if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
+ if (options.insertLeft) marker.widgetNode.insertLeft = true;
+ }
+ if (marker.collapsed) {
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
+ throw new Error("Inserting collapsed marker partially overlapping an existing one");
+ sawCollapsedSpans = true;
+ }
+
+ if (marker.addToHistory)
+ addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
+
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
+ doc.iter(curLine, to.line + 1, function(line) {
+ if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
+ updateMaxLine = true;
+ if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
+ addMarkedSpan(line, new MarkedSpan(marker,
+ curLine == from.line ? from.ch : null,
+ curLine == to.line ? to.ch : null));
+ ++curLine;
+ });
+ // lineIsHidden depends on the presence of the spans, so needs a second pass
+ if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
+ if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
+ });
+
+ if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
+
+ if (marker.readOnly) {
+ sawReadOnlySpans = true;
+ if (doc.history.done.length || doc.history.undone.length)
+ doc.clearHistory();
+ }
+ if (marker.collapsed) {
+ marker.id = ++nextMarkerId;
+ marker.atomic = true;
+ }
+ if (cm) {
+ // Sync editor state
+ if (updateMaxLine) cm.curOp.updateMaxLine = true;
+ if (marker.collapsed)
+ regChange(cm, from.line, to.line + 1);
+ else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
+ for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
+ if (marker.atomic) reCheckSelection(cm.doc);
+ signalLater(cm, "markerAdded", cm, marker);
+ }
+ return marker;
+ }
+
+ // SHARED TEXTMARKERS
+
+ // A shared marker spans multiple linked documents. It is
+ // implemented as a meta-marker-object controlling multiple normal
+ // markers.
+ var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
+ this.markers = markers;
+ this.primary = primary;
+ for (var i = 0; i < markers.length; ++i)
+ markers[i].parent = this;
+ };
+ eventMixin(SharedTextMarker);
+
+ SharedTextMarker.prototype.clear = function() {
+ if (this.explicitlyCleared) return;
+ this.explicitlyCleared = true;
+ for (var i = 0; i < this.markers.length; ++i)
+ this.markers[i].clear();
+ signalLater(this, "clear");
+ };
+ SharedTextMarker.prototype.find = function(side, lineObj) {
+ return this.primary.find(side, lineObj);
+ };
+
+ function markTextShared(doc, from, to, options, type) {
+ options = copyObj(options);
+ options.shared = false;
+ var markers = [markText(doc, from, to, options, type)], primary = markers[0];
+ var widget = options.widgetNode;
+ linkedDocs(doc, function(doc) {
+ if (widget) options.widgetNode = widget.cloneNode(true);
+ markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
+ for (var i = 0; i < doc.linked.length; ++i)
+ if (doc.linked[i].isParent) return;
+ primary = lst(markers);
+ });
+ return new SharedTextMarker(markers, primary);
+ }
+
+ function findSharedMarkers(doc) {
+ return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
+ function(m) { return m.parent; });
+ }
+
+ function copySharedMarkers(doc, markers) {
+ for (var i = 0; i < markers.length; i++) {
+ var marker = markers[i], pos = marker.find();
+ var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
+ if (cmp(mFrom, mTo)) {
+ var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
+ marker.markers.push(subMark);
+ subMark.parent = marker;
+ }
+ }
+ }
+
+ function detachSharedMarkers(markers) {
+ for (var i = 0; i < markers.length; i++) {
+ var marker = markers[i], linked = [marker.primary.doc];;
+ linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
+ for (var j = 0; j < marker.markers.length; j++) {
+ var subMarker = marker.markers[j];
+ if (indexOf(linked, subMarker.doc) == -1) {
+ subMarker.parent = null;
+ marker.markers.splice(j--, 1);
+ }
+ }
+ }
+ }
+
+ // TEXTMARKER SPANS
+
+ function MarkedSpan(marker, from, to) {
+ this.marker = marker;
+ this.from = from; this.to = to;
+ }
+
+ // Search an array of spans for a span matching the given marker.
+ function getMarkedSpanFor(spans, marker) {
+ if (spans) for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.marker == marker) return span;
+ }
+ }
+ // Remove a span from an array, returning undefined if no spans are
+ // left (we don't store arrays for lines without spans).
+ function removeMarkedSpan(spans, span) {
+ for (var r, i = 0; i < spans.length; ++i)
+ if (spans[i] != span) (r || (r = [])).push(spans[i]);
+ return r;
+ }
+ // Add a span to a line.
+ function addMarkedSpan(line, span) {
+ line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
+ span.marker.attachLine(line);
+ }
+
+ // Used for the algorithm that adjusts markers for a change in the
+ // document. These functions cut an array of spans at a given
+ // character position, returning an array of remaining chunks (or
+ // undefined if nothing remains).
+ function markedSpansBefore(old, startCh, isInsert) {
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
+ var span = old[i], marker = span.marker;
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
+ (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
+ }
+ }
+ return nw;
+ }
+ function markedSpansAfter(old, endCh, isInsert) {
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
+ var span = old[i], marker = span.marker;
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
+ (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
+ span.to == null ? null : span.to - endCh));
+ }
+ }
+ return nw;
+ }
+
+ // Given a change object, compute the new set of marker spans that
+ // cover the line in which the change took place. Removes spans
+ // entirely within the change, reconnects spans belonging to the
+ // same marker that appear on both sides of the change, and cuts off
+ // spans partially within the change. Returns an array of span
+ // arrays with one element for each line in (after) the change.
+ function stretchSpansOverChange(doc, change) {
+ var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
+ var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
+ if (!oldFirst && !oldLast) return null;
+
+ var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
+ // Get the spans that 'stick out' on both sides
+ var first = markedSpansBefore(oldFirst, startCh, isInsert);
+ var last = markedSpansAfter(oldLast, endCh, isInsert);
+
+ // Next, merge those two ends
+ var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
+ if (first) {
+ // Fix up .to properties of first
+ for (var i = 0; i < first.length; ++i) {
+ var span = first[i];
+ if (span.to == null) {
+ var found = getMarkedSpanFor(last, span.marker);
+ if (!found) span.to = startCh;
+ else if (sameLine) span.to = found.to == null ? null : found.to + offset;
+ }
+ }
+ }
+ if (last) {
+ // Fix up .from in last (or move them into first in case of sameLine)
+ for (var i = 0; i < last.length; ++i) {
+ var span = last[i];
+ if (span.to != null) span.to += offset;
+ if (span.from == null) {
+ var found = getMarkedSpanFor(first, span.marker);
+ if (!found) {
+ span.from = offset;
+ if (sameLine) (first || (first = [])).push(span);
+ }
+ } else {
+ span.from += offset;
+ if (sameLine) (first || (first = [])).push(span);
+ }
+ }
+ }
+ // Make sure we didn't create any zero-length spans
+ if (first) first = clearEmptySpans(first);
+ if (last && last != first) last = clearEmptySpans(last);
+
+ var newMarkers = [first];
+ if (!sameLine) {
+ // Fill gap with whole-line-spans
+ var gap = change.text.length - 2, gapMarkers;
+ if (gap > 0 && first)
+ for (var i = 0; i < first.length; ++i)
+ if (first[i].to == null)
+ (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
+ for (var i = 0; i < gap; ++i)
+ newMarkers.push(gapMarkers);
+ newMarkers.push(last);
+ }
+ return newMarkers;
+ }
+
+ // Remove spans that are empty and don't have a clearWhenEmpty
+ // option of false.
+ function clearEmptySpans(spans) {
+ for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
+ spans.splice(i--, 1);
+ }
+ if (!spans.length) return null;
+ return spans;
+ }
+
+ // Used for un/re-doing changes from the history. Combines the
+ // result of computing the existing spans with the set of spans that
+ // existed in the history (so that deleting around a span and then
+ // undoing brings back the span).
+ function mergeOldSpans(doc, change) {
+ var old = getOldSpans(doc, change);
+ var stretched = stretchSpansOverChange(doc, change);
+ if (!old) return stretched;
+ if (!stretched) return old;
+
+ for (var i = 0; i < old.length; ++i) {
+ var oldCur = old[i], stretchCur = stretched[i];
+ if (oldCur && stretchCur) {
+ spans: for (var j = 0; j < stretchCur.length; ++j) {
+ var span = stretchCur[j];
+ for (var k = 0; k < oldCur.length; ++k)
+ if (oldCur[k].marker == span.marker) continue spans;
+ oldCur.push(span);
+ }
+ } else if (stretchCur) {
+ old[i] = stretchCur;
+ }
+ }
+ return old;
+ }
+
+ // Used to 'clip' out readOnly ranges when making a change.
+ function removeReadOnlyRanges(doc, from, to) {
+ var markers = null;
+ doc.iter(from.line, to.line + 1, function(line) {
+ if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
+ var mark = line.markedSpans[i].marker;
+ if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
+ (markers || (markers = [])).push(mark);
+ }
+ });
+ if (!markers) return null;
+ var parts = [{from: from, to: to}];
+ for (var i = 0; i < markers.length; ++i) {
+ var mk = markers[i], m = mk.find(0);
+ for (var j = 0; j < parts.length; ++j) {
+ var p = parts[j];
+ if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
+ var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
+ if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
+ newParts.push({from: p.from, to: m.from});
+ if (dto > 0 || !mk.inclusiveRight && !dto)
+ newParts.push({from: m.to, to: p.to});
+ parts.splice.apply(parts, newParts);
+ j += newParts.length - 1;
+ }
+ }
+ return parts;
+ }
+
+ // Connect or disconnect spans from a line.
+ function detachMarkedSpans(line) {
+ var spans = line.markedSpans;
+ if (!spans) return;
+ for (var i = 0; i < spans.length; ++i)
+ spans[i].marker.detachLine(line);
+ line.markedSpans = null;
+ }
+ function attachMarkedSpans(line, spans) {
+ if (!spans) return;
+ for (var i = 0; i < spans.length; ++i)
+ spans[i].marker.attachLine(line);
+ line.markedSpans = spans;
+ }
+
+ // Helpers used when computing which overlapping collapsed span
+ // counts as the larger one.
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
+
+ // Returns a number indicating which of two overlapping collapsed
+ // spans is larger (and thus includes the other). Falls back to
+ // comparing ids when the spans cover exactly the same range.
+ function compareCollapsedMarkers(a, b) {
+ var lenDiff = a.lines.length - b.lines.length;
+ if (lenDiff != 0) return lenDiff;
+ var aPos = a.find(), bPos = b.find();
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
+ if (fromCmp) return -fromCmp;
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
+ if (toCmp) return toCmp;
+ return b.id - a.id;
+ }
+
+ // Find out whether a line ends or starts in a collapsed span. If
+ // so, return the marker for that span.
+ function collapsedSpanAtSide(line, start) {
+ var sps = sawCollapsedSpans && line.markedSpans, found;
+ if (sps) for (var sp, i = 0; i < sps.length; ++i) {
+ sp = sps[i];
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
+ found = sp.marker;
+ }
+ return found;
+ }
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
+
+ // Test whether there exists a collapsed span that partially
+ // overlaps (covers the start or end, but not both) of a new span.
+ // Such overlap is not allowed.
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
+ var line = getLine(doc, lineNo);
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) for (var i = 0; i < sps.length; ++i) {
+ var sp = sps[i];
+ if (!sp.marker.collapsed) continue;
+ var found = sp.marker.find(0);
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
+ if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
+ fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
+ return true;
+ }
+ }
+
+ // A visual line is a line as drawn on the screen. Folding, for
+ // example, can cause multiple logical lines to appear on the same
+ // visual line. This finds the start of the visual line that the
+ // given line is part of (usually that is the line itself).
+ function visualLine(line) {
+ var merged;
+ while (merged = collapsedSpanAtStart(line))
+ line = merged.find(-1, true).line;
+ return line;
+ }
+
+ // Returns an array of logical lines that continue the visual line
+ // started by the argument, or undefined if there are no such lines.
+ function visualLineContinued(line) {
+ var merged, lines;
+ while (merged = collapsedSpanAtEnd(line)) {
+ line = merged.find(1, true).line;
+ (lines || (lines = [])).push(line);
+ }
+ return lines;
+ }
+
+ // Get the line number of the start of the visual line that the
+ // given line number is part of.
+ function visualLineNo(doc, lineN) {
+ var line = getLine(doc, lineN), vis = visualLine(line);
+ if (line == vis) return lineN;
+ return lineNo(vis);
+ }
+ // Get the line number of the start of the next visual line after
+ // the given line.
+ function visualLineEndNo(doc, lineN) {
+ if (lineN > doc.lastLine()) return lineN;
+ var line = getLine(doc, lineN), merged;
+ if (!lineIsHidden(doc, line)) return lineN;
+ while (merged = collapsedSpanAtEnd(line))
+ line = merged.find(1, true).line;
+ return lineNo(line) + 1;
+ }
+
+ // Compute whether a line is hidden. Lines count as hidden when they
+ // are part of a visual line that starts with another line, or when
+ // they are entirely covered by collapsed, non-widget span.
+ function lineIsHidden(doc, line) {
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) for (var sp, i = 0; i < sps.length; ++i) {
+ sp = sps[i];
+ if (!sp.marker.collapsed) continue;
+ if (sp.from == null) return true;
+ if (sp.marker.widgetNode) continue;
+ if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
+ return true;
+ }
+ }
+ function lineIsHiddenInner(doc, line, span) {
+ if (span.to == null) {
+ var end = span.marker.find(1, true);
+ return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
+ }
+ if (span.marker.inclusiveRight && span.to == line.text.length)
+ return true;
+ for (var sp, i = 0; i < line.markedSpans.length; ++i) {
+ sp = line.markedSpans[i];
+ if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
+ (sp.to == null || sp.to != span.from) &&
+ (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
+ lineIsHiddenInner(doc, line, sp)) return true;
+ }
+ }
+
+ // LINE WIDGETS
+
+ // Line widgets are block elements displayed above or below a line.
+
+ var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
+ if (options) for (var opt in options) if (options.hasOwnProperty(opt))
+ this[opt] = options[opt];
+ this.cm = cm;
+ this.node = node;
+ };
+ eventMixin(LineWidget);
+
+ function adjustScrollWhenAboveVisible(cm, line, diff) {
+ if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
+ addToScrollPos(cm, null, diff);
+ }
+
+ LineWidget.prototype.clear = function() {
+ var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
+ if (no == null || !ws) return;
+ for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
+ if (!ws.length) line.widgets = null;
+ var height = widgetHeight(this);
+ runInOp(cm, function() {
+ adjustScrollWhenAboveVisible(cm, line, -height);
+ regLineChange(cm, no, "widget");
+ updateLineHeight(line, Math.max(0, line.height - height));
+ });
+ };
+ LineWidget.prototype.changed = function() {
+ var oldH = this.height, cm = this.cm, line = this.line;
+ this.height = null;
+ var diff = widgetHeight(this) - oldH;
+ if (!diff) return;
+ runInOp(cm, function() {
+ cm.curOp.forceUpdate = true;
+ adjustScrollWhenAboveVisible(cm, line, diff);
+ updateLineHeight(line, line.height + diff);
+ });
+ };
+
+ function widgetHeight(widget) {
+ if (widget.height != null) return widget.height;
+ if (!contains(document.body, widget.node)) {
+ var parentStyle = "position: relative;";
+ if (widget.coverGutter)
+ parentStyle += "margin-left: -" + widget.cm.getGutterElement().offsetWidth + "px;";
+ removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, parentStyle));
+ }
+ return widget.height = widget.node.offsetHeight;
+ }
+
+ function addLineWidget(cm, handle, node, options) {
+ var widget = new LineWidget(cm, node, options);
+ if (widget.noHScroll) cm.display.alignWidgets = true;
+ changeLine(cm.doc, handle, "widget", function(line) {
+ var widgets = line.widgets || (line.widgets = []);
+ if (widget.insertAt == null) widgets.push(widget);
+ else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
+ widget.line = line;
+ if (!lineIsHidden(cm.doc, line)) {
+ var aboveVisible = heightAtLine(line) < cm.doc.scrollTop;
+ updateLineHeight(line, line.height + widgetHeight(widget));
+ if (aboveVisible) addToScrollPos(cm, null, widget.height);
+ cm.curOp.forceUpdate = true;
+ }
+ return true;
+ });
+ return widget;
+ }
+
+ // LINE DATA STRUCTURE
+
+ // Line objects. These hold state related to a line, including
+ // highlighting info (the styles array).
+ var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
+ this.text = text;
+ attachMarkedSpans(this, markedSpans);
+ this.height = estimateHeight ? estimateHeight(this) : 1;
+ };
+ eventMixin(Line);
+ Line.prototype.lineNo = function() { return lineNo(this); };
+
+ // Change the content (text, markers) of a line. Automatically
+ // invalidates cached information and tries to re-estimate the
+ // line's height.
+ function updateLine(line, text, markedSpans, estimateHeight) {
+ line.text = text;
+ if (line.stateAfter) line.stateAfter = null;
+ if (line.styles) line.styles = null;
+ if (line.order != null) line.order = null;
+ detachMarkedSpans(line);
+ attachMarkedSpans(line, markedSpans);
+ var estHeight = estimateHeight ? estimateHeight(line) : 1;
+ if (estHeight != line.height) updateLineHeight(line, estHeight);
+ }
+
+ // Detach a line from the document tree and its markers.
+ function cleanUpLine(line) {
+ line.parent = null;
+ detachMarkedSpans(line);
+ }
+
+ function extractLineClasses(type, output) {
+ if (type) for (;;) {
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
+ if (!lineClass) break;
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
+ var prop = lineClass[1] ? "bgClass" : "textClass";
+ if (output[prop] == null)
+ output[prop] = lineClass[2];
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
+ output[prop] += " " + lineClass[2];
+ }
+ return type;
+ }
+
+ function callBlankLine(mode, state) {
+ if (mode.blankLine) return mode.blankLine(state);
+ if (!mode.innerMode) return;
+ var inner = CodeMirror.innerMode(mode, state);
+ if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
+ }
+
+ function readToken(mode, stream, state) {
+ for (var i = 0; i < 10; i++) {
+ var style = mode.token(stream, state);
+ if (stream.pos > stream.start) return style;
+ }
+ throw new Error("Mode " + mode.name + " failed to advance stream.");
+ }
+
+ // Run the given mode's parser over a line, calling f for each token.
+ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
+ var flattenSpans = mode.flattenSpans;
+ if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
+ var curStart = 0, curStyle = null;
+ var stream = new StringStream(text, cm.options.tabSize), style;
+ if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
+ while (!stream.eol()) {
+ if (stream.pos > cm.options.maxHighlightLength) {
+ flattenSpans = false;
+ if (forceToEnd) processLine(cm, text, state, stream.pos);
+ stream.pos = text.length;
+ style = null;
+ } else {
+ style = extractLineClasses(readToken(mode, stream, state), lineClasses);
+ }
+ if (cm.options.addModeClass) {
+ var mName = CodeMirror.innerMode(mode, state).mode.name;
+ if (mName) style = "m-" + (style ? mName + " " + style : mName);
+ }
+ if (!flattenSpans || curStyle != style) {
+ if (curStart < stream.start) f(stream.start, curStyle);
+ curStart = stream.start; curStyle = style;
+ }
+ stream.start = stream.pos;
+ }
+ while (curStart < stream.pos) {
+ // Webkit seems to refuse to render text nodes longer than 57444 characters
+ var pos = Math.min(stream.pos, curStart + 50000);
+ f(pos, curStyle);
+ curStart = pos;
+ }
+ }
+
+ // Compute a style array (an array starting with a mode generation
+ // -- for invalidation -- followed by pairs of end positions and
+ // style strings), which is used to highlight the tokens on the
+ // line.
+ function highlightLine(cm, line, state, forceToEnd) {
+ // A styles array always starts with a number identifying the
+ // mode/overlays that it is based on (for easy invalidation).
+ var st = [cm.state.modeGen], lineClasses = {};
+ // Compute the base array of styles
+ runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
+ st.push(end, style);
+ }, lineClasses, forceToEnd);
+
+ // Run overlays, adjust style array.
+ for (var o = 0; o < cm.state.overlays.length; ++o) {
+ var overlay = cm.state.overlays[o], i = 1, at = 0;
+ runMode(cm, line.text, overlay.mode, true, function(end, style) {
+ var start = i;
+ // Ensure there's a token end at the current position, and that i points at it
+ while (at < end) {
+ var i_end = st[i];
+ if (i_end > end)
+ st.splice(i, 1, end, st[i+1], i_end);
+ i += 2;
+ at = Math.min(end, i_end);
+ }
+ if (!style) return;
+ if (overlay.opaque) {
+ st.splice(start, i - start, end, "cm-overlay " + style);
+ i = start + 2;
+ } else {
+ for (; start < i; start += 2) {
+ var cur = st[start+1];
+ st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
+ }
+ }
+ }, lineClasses);
+ }
+
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
+ }
+
+ function getLineStyles(cm, line) {
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
+ var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+ line.styles = result.styles;
+ if (result.classes) line.styleClasses = result.classes;
+ else if (line.styleClasses) line.styleClasses = null;
+ }
+ return line.styles;
+ }
+
+ // Lightweight form of highlight -- proceed over this line and
+ // update state, but don't save a style array. Used for lines that
+ // aren't currently visible.
+ function processLine(cm, text, state, startAt) {
+ var mode = cm.doc.mode;
+ var stream = new StringStream(text, cm.options.tabSize);
+ stream.start = stream.pos = startAt || 0;
+ if (text == "") callBlankLine(mode, state);
+ while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
+ readToken(mode, stream, state);
+ stream.start = stream.pos;
+ }
+ }
+
+ // Convert a style as returned by a mode (either null, or a string
+ // containing one or more styles) to a CSS style. This is cached,
+ // and also looks for line-wide styles.
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
+ function interpretTokenStyle(style, options) {
+ if (!style || /^\s*$/.test(style)) return null;
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+ return cache[style] ||
+ (cache[style] = style.replace(/\S+/g, "cm-$&"));
+ }
+
+ // Render the DOM representation of the text of a line. Also builds
+ // up a 'line map', which points at the DOM nodes that represent
+ // specific stretches of text, and is used by the measuring code.
+ // The returned object contains the DOM node, this map, and
+ // information about line-wide styles that were set by the mode.
+ function buildLineContent(cm, lineView) {
+ // The padding-right forces the element to have a 'border', which
+ // is needed on Webkit to be able to get line-level bounding
+ // rectangles for it (in measureChar).
+ var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
+ var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm};
+ lineView.measure = {};
+
+ // Iterate over the logical lines that make up this visual line.
+ for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
+ var line = i ? lineView.rest[i - 1] : lineView.line, order;
+ builder.pos = 0;
+ builder.addToken = buildToken;
+ // Optionally wire in some hacks into the token-rendering
+ // algorithm, to deal with browser quirks.
+ if ((ie || webkit) && cm.getOption("lineWrapping"))
+ builder.addToken = buildTokenSplitSpaces(builder.addToken);
+ if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
+ builder.addToken = buildTokenBadBidi(builder.addToken, order);
+ builder.map = [];
+ insertLineContent(line, builder, getLineStyles(cm, line));
+ if (line.styleClasses) {
+ if (line.styleClasses.bgClass)
+ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
+ if (line.styleClasses.textClass)
+ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
+ }
+
+ // Ensure at least a single node is present, for measuring.
+ if (builder.map.length == 0)
+ builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
+
+ // Store the map and a cache object for the current logical line
+ if (i == 0) {
+ lineView.measure.map = builder.map;
+ lineView.measure.cache = {};
+ } else {
+ (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
+ (lineView.measure.caches || (lineView.measure.caches = [])).push({});
+ }
+ }
+
+ signal(cm, "renderLine", cm, lineView.line, builder.pre);
+ if (builder.pre.className)
+ builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
+ return builder;
+ }
+
+ function defaultSpecialCharPlaceholder(ch) {
+ var token = elt("span", "\u2022", "cm-invalidchar");
+ token.title = "\\u" + ch.charCodeAt(0).toString(16);
+ return token;
+ }
+
+ // Build up the DOM representation for a single token, and add it to
+ // the line map. Takes care to render special characters separately.
+ function buildToken(builder, text, style, startStyle, endStyle, title) {
+ if (!text) return;
+ var special = builder.cm.options.specialChars, mustWrap = false;
+ if (!special.test(text)) {
+ builder.col += text.length;
+ var content = document.createTextNode(text);
+ builder.map.push(builder.pos, builder.pos + text.length, content);
+ if (ie && ie_version < 9) mustWrap = true;
+ builder.pos += text.length;
+ } else {
+ var content = document.createDocumentFragment(), pos = 0;
+ while (true) {
+ special.lastIndex = pos;
+ var m = special.exec(text);
+ var skipped = m ? m.index - pos : text.length - pos;
+ if (skipped) {
+ var txt = document.createTextNode(text.slice(pos, pos + skipped));
+ if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
+ else content.appendChild(txt);
+ builder.map.push(builder.pos, builder.pos + skipped, txt);
+ builder.col += skipped;
+ builder.pos += skipped;
+ }
+ if (!m) break;
+ pos += skipped + 1;
+ if (m[0] == "\t") {
+ var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
+ var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
+ builder.col += tabWidth;
+ } else {
+ var txt = builder.cm.options.specialCharPlaceholder(m[0]);
+ if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
+ else content.appendChild(txt);
+ builder.col += 1;
+ }
+ builder.map.push(builder.pos, builder.pos + 1, txt);
+ builder.pos++;
+ }
+ }
+ if (style || startStyle || endStyle || mustWrap) {
+ var fullStyle = style || "";
+ if (startStyle) fullStyle += startStyle;
+ if (endStyle) fullStyle += endStyle;
+ var token = elt("span", [content], fullStyle);
+ if (title) token.title = title;
+ return builder.content.appendChild(token);
+ }
+ builder.content.appendChild(content);
+ }
+
+ function buildTokenSplitSpaces(inner) {
+ function split(old) {
+ var out = " ";
+ for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
+ out += " ";
+ return out;
+ }
+ return function(builder, text, style, startStyle, endStyle, title) {
+ inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
+ };
+ }
+
+ // Work around nonsense dimensions being reported for stretches of
+ // right-to-left text.
+ function buildTokenBadBidi(inner, order) {
+ return function(builder, text, style, startStyle, endStyle, title) {
+ style = style ? style + " cm-force-border" : "cm-force-border";
+ var start = builder.pos, end = start + text.length;
+ for (;;) {
+ // Find the part that overlaps with the start of this text
+ for (var i = 0; i < order.length; i++) {
+ var part = order[i];
+ if (part.to > start && part.from <= start) break;
+ }
+ if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title);
+ inner(builder, text.slice(0, part.to - start), style, startStyle, null, title);
+ startStyle = null;
+ text = text.slice(part.to - start);
+ start = part.to;
+ }
+ };
+ }
+
+ function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
+ var widget = !ignoreWidget && marker.widgetNode;
+ if (widget) {
+ builder.map.push(builder.pos, builder.pos + size, widget);
+ builder.content.appendChild(widget);
+ }
+ builder.pos += size;
+ }
+
+ // Outputs a number of spans to make up a line, taking highlighting
+ // and marked text into account.
+ function insertLineContent(line, builder, styles) {
+ var spans = line.markedSpans, allText = line.text, at = 0;
+ if (!spans) {
+ for (var i = 1; i < styles.length; i+=2)
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
+ return;
+ }
+
+ var len = allText.length, pos = 0, i = 1, text = "", style;
+ var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
+ for (;;) {
+ if (nextChange == pos) { // Update current marker set
+ spanStyle = spanEndStyle = spanStartStyle = title = "";
+ collapsed = null; nextChange = Infinity;
+ var foundBookmarks = [];
+ for (var j = 0; j < spans.length; ++j) {
+ var sp = spans[j], m = sp.marker;
+ if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
+ if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
+ if (m.className) spanStyle += " " + m.className;
+ if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
+ if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
+ if (m.title && !title) title = m.title;
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
+ collapsed = sp;
+ } else if (sp.from > pos && nextChange > sp.from) {
+ nextChange = sp.from;
+ }
+ if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m);
+ }
+ if (collapsed && (collapsed.from || 0) == pos) {
+ buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
+ collapsed.marker, collapsed.from == null);
+ if (collapsed.to == null) return;
+ }
+ if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
+ buildCollapsedSpan(builder, 0, foundBookmarks[j]);
+ }
+ if (pos >= len) break;
+
+ var upto = Math.min(len, nextChange);
+ while (true) {
+ if (text) {
+ var end = pos + text.length;
+ if (!collapsed) {
+ var tokenText = end > upto ? text.slice(0, upto - pos) : text;
+ builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
+ }
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
+ pos = end;
+ spanStartStyle = "";
+ }
+ text = allText.slice(at, at = styles[i++]);
+ style = interpretTokenStyle(styles[i++], builder.cm.options);
+ }
+ }
+ }
+
+ // DOCUMENT DATA STRUCTURE
+
+ // By default, updates that start and end at the beginning of a line
+ // are treated specially, in order to make the association of line
+ // widgets and marker elements with the text behave more intuitive.
+ function isWholeLineUpdate(doc, change) {
+ return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
+ }
+
+ // Perform a change on the document data structure.
+ function updateDoc(doc, change, markedSpans, estimateHeight) {
+ function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
+ function update(line, text, spans) {
+ updateLine(line, text, spans, estimateHeight);
+ signalLater(line, "change", line, change);
+ }
+
+ var from = change.from, to = change.to, text = change.text;
+ var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
+ var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
+
+ // Adjust the line structure
+ if (isWholeLineUpdate(doc, change)) {
+ // This is a whole-line replace. Treated specially to make
+ // sure line objects move the way they are supposed to.
+ for (var i = 0, added = []; i < text.length - 1; ++i)
+ added.push(new Line(text[i], spansFor(i), estimateHeight));
+ update(lastLine, lastLine.text, lastSpans);
+ if (nlines) doc.remove(from.line, nlines);
+ if (added.length) doc.insert(from.line, added);
+ } else if (firstLine == lastLine) {
+ if (text.length == 1) {
+ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
+ } else {
+ for (var added = [], i = 1; i < text.length - 1; ++i)
+ added.push(new Line(text[i], spansFor(i), estimateHeight));
+ added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+ doc.insert(from.line + 1, added);
+ }
+ } else if (text.length == 1) {
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
+ doc.remove(from.line + 1, nlines);
+ } else {
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+ update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
+ for (var i = 1, added = []; i < text.length - 1; ++i)
+ added.push(new Line(text[i], spansFor(i), estimateHeight));
+ if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
+ doc.insert(from.line + 1, added);
+ }
+
+ signalLater(doc, "change", doc, change);
+ }
+
+ // The document is represented as a BTree consisting of leaves, with
+ // chunk of lines in them, and branches, with up to ten leaves or
+ // other branch nodes below them. The top node is always a branch
+ // node, and is the document object itself (meaning it has
+ // additional methods and properties).
+ //
+ // All nodes have parent links. The tree is used both to go from
+ // line numbers to line objects, and to go from objects to numbers.
+ // It also indexes by height, and is used to convert between height
+ // and line object, and to find the total height of the document.
+ //
+ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
+
+ function LeafChunk(lines) {
+ this.lines = lines;
+ this.parent = null;
+ for (var i = 0, height = 0; i < lines.length; ++i) {
+ lines[i].parent = this;
+ height += lines[i].height;
+ }
+ this.height = height;
+ }
+
+ LeafChunk.prototype = {
+ chunkSize: function() { return this.lines.length; },
+ // Remove the n lines at offset 'at'.
+ removeInner: function(at, n) {
+ for (var i = at, e = at + n; i < e; ++i) {
+ var line = this.lines[i];
+ this.height -= line.height;
+ cleanUpLine(line);
+ signalLater(line, "delete");
+ }
+ this.lines.splice(at, n);
+ },
+ // Helper used to collapse a small branch into a single leaf.
+ collapse: function(lines) {
+ lines.push.apply(lines, this.lines);
+ },
+ // Insert the given array of lines at offset 'at', count them as
+ // having the given height.
+ insertInner: function(at, lines, height) {
+ this.height += height;
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
+ for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
+ },
+ // Used to iterate over a part of the tree.
+ iterN: function(at, n, op) {
+ for (var e = at + n; at < e; ++at)
+ if (op(this.lines[at])) return true;
+ }
+ };
+
+ function BranchChunk(children) {
+ this.children = children;
+ var size = 0, height = 0;
+ for (var i = 0; i < children.length; ++i) {
+ var ch = children[i];
+ size += ch.chunkSize(); height += ch.height;
+ ch.parent = this;
+ }
+ this.size = size;
+ this.height = height;
+ this.parent = null;
+ }
+
+ BranchChunk.prototype = {
+ chunkSize: function() { return this.size; },
+ removeInner: function(at, n) {
+ this.size -= n;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var rm = Math.min(n, sz - at), oldHeight = child.height;
+ child.removeInner(at, rm);
+ this.height -= oldHeight - child.height;
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
+ if ((n -= rm) == 0) break;
+ at = 0;
+ } else at -= sz;
+ }
+ // If the result is smaller than 25 lines, ensure that it is a
+ // single leaf node.
+ if (this.size - n < 25 &&
+ (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
+ var lines = [];
+ this.collapse(lines);
+ this.children = [new LeafChunk(lines)];
+ this.children[0].parent = this;
+ }
+ },
+ collapse: function(lines) {
+ for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
+ },
+ insertInner: function(at, lines, height) {
+ this.size += lines.length;
+ this.height += height;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at <= sz) {
+ child.insertInner(at, lines, height);
+ if (child.lines && child.lines.length > 50) {
+ while (child.lines.length > 50) {
+ var spilled = child.lines.splice(child.lines.length - 25, 25);
+ var newleaf = new LeafChunk(spilled);
+ child.height -= newleaf.height;
+ this.children.splice(i + 1, 0, newleaf);
+ newleaf.parent = this;
+ }
+ this.maybeSpill();
+ }
+ break;
+ }
+ at -= sz;
+ }
+ },
+ // When a node has grown, check whether it should be split.
+ maybeSpill: function() {
+ if (this.children.length <= 10) return;
+ var me = this;
+ do {
+ var spilled = me.children.splice(me.children.length - 5, 5);
+ var sibling = new BranchChunk(spilled);
+ if (!me.parent) { // Become the parent node
+ var copy = new BranchChunk(me.children);
+ copy.parent = me;
+ me.children = [copy, sibling];
+ me = copy;
+ } else {
+ me.size -= sibling.size;
+ me.height -= sibling.height;
+ var myIndex = indexOf(me.parent.children, me);
+ me.parent.children.splice(myIndex + 1, 0, sibling);
+ }
+ sibling.parent = me.parent;
+ } while (me.children.length > 10);
+ me.parent.maybeSpill();
+ },
+ iterN: function(at, n, op) {
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var used = Math.min(n, sz - at);
+ if (child.iterN(at, used, op)) return true;
+ if ((n -= used) == 0) break;
+ at = 0;
+ } else at -= sz;
+ }
+ }
+ };
+
+ var nextDocId = 0;
+ var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
+ if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
+ if (firstLine == null) firstLine = 0;
+
+ BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
+ this.first = firstLine;
+ this.scrollTop = this.scrollLeft = 0;
+ this.cantEdit = false;
+ this.cleanGeneration = 1;
+ this.frontier = firstLine;
+ var start = Pos(firstLine, 0);
+ this.sel = simpleSelection(start);
+ this.history = new History(null);
+ this.id = ++nextDocId;
+ this.modeOption = mode;
+
+ if (typeof text == "string") text = splitLines(text);
+ updateDoc(this, {from: start, to: start, text: text});
+ setSelection(this, simpleSelection(start), sel_dontScroll);
+ };
+
+ Doc.prototype = createObj(BranchChunk.prototype, {
+ constructor: Doc,
+ // Iterate over the document. Supports two forms -- with only one
+ // argument, it calls that for each line in the document. With
+ // three, it iterates over the range given by the first two (with
+ // the second being non-inclusive).
+ iter: function(from, to, op) {
+ if (op) this.iterN(from - this.first, to - from, op);
+ else this.iterN(this.first, this.first + this.size, from);
+ },
+
+ // Non-public interface for adding and removing lines.
+ insert: function(at, lines) {
+ var height = 0;
+ for (var i = 0; i < lines.length; ++i) height += lines[i].height;
+ this.insertInner(at - this.first, lines, height);
+ },
+ remove: function(at, n) { this.removeInner(at - this.first, n); },
+
+ // From here, the methods are part of the public interface. Most
+ // are also available from CodeMirror (editor) instances.
+
+ getValue: function(lineSep) {
+ var lines = getLines(this, this.first, this.first + this.size);
+ if (lineSep === false) return lines;
+ return lines.join(lineSep || "\n");
+ },
+ setValue: docMethodOp(function(code) {
+ var top = Pos(this.first, 0), last = this.first + this.size - 1;
+ makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
+ text: splitLines(code), origin: "setValue"}, true);
+ setSelection(this, simpleSelection(top));
+ }),
+ replaceRange: function(code, from, to, origin) {
+ from = clipPos(this, from);
+ to = to ? clipPos(this, to) : from;
+ replaceRange(this, code, from, to, origin);
+ },
+ getRange: function(from, to, lineSep) {
+ var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
+ if (lineSep === false) return lines;
+ return lines.join(lineSep || "\n");
+ },
+
+ getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
+
+ getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
+ getLineNumber: function(line) {return lineNo(line);},
+
+ getLineHandleVisualStart: function(line) {
+ if (typeof line == "number") line = getLine(this, line);
+ return visualLine(line);
+ },
+
+ lineCount: function() {return this.size;},
+ firstLine: function() {return this.first;},
+ lastLine: function() {return this.first + this.size - 1;},
+
+ clipPos: function(pos) {return clipPos(this, pos);},
+
+ getCursor: function(start) {
+ var range = this.sel.primary(), pos;
+ if (start == null || start == "head") pos = range.head;
+ else if (start == "anchor") pos = range.anchor;
+ else if (start == "end" || start == "to" || start === false) pos = range.to();
+ else pos = range.from();
+ return pos;
+ },
+ listSelections: function() { return this.sel.ranges; },
+ somethingSelected: function() {return this.sel.somethingSelected();},
+
+ setCursor: docMethodOp(function(line, ch, options) {
+ setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
+ }),
+ setSelection: docMethodOp(function(anchor, head, options) {
+ setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
+ }),
+ extendSelection: docMethodOp(function(head, other, options) {
+ extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
+ }),
+ extendSelections: docMethodOp(function(heads, options) {
+ extendSelections(this, clipPosArray(this, heads, options));
+ }),
+ extendSelectionsBy: docMethodOp(function(f, options) {
+ extendSelections(this, map(this.sel.ranges, f), options);
+ }),
+ setSelections: docMethodOp(function(ranges, primary, options) {
+ if (!ranges.length) return;
+ for (var i = 0, out = []; i < ranges.length; i++)
+ out[i] = new Range(clipPos(this, ranges[i].anchor),
+ clipPos(this, ranges[i].head));
+ if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
+ setSelection(this, normalizeSelection(out, primary), options);
+ }),
+ addSelection: docMethodOp(function(anchor, head, options) {
+ var ranges = this.sel.ranges.slice(0);
+ ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
+ setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
+ }),
+
+ getSelection: function(lineSep) {
+ var ranges = this.sel.ranges, lines;
+ for (var i = 0; i < ranges.length; i++) {
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+ lines = lines ? lines.concat(sel) : sel;
+ }
+ if (lineSep === false) return lines;
+ else return lines.join(lineSep || "\n");
+ },
+ getSelections: function(lineSep) {
+ var parts = [], ranges = this.sel.ranges;
+ for (var i = 0; i < ranges.length; i++) {
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+ if (lineSep !== false) sel = sel.join(lineSep || "\n");
+ parts[i] = sel;
+ }
+ return parts;
+ },
+ replaceSelection: function(code, collapse, origin) {
+ var dup = [];
+ for (var i = 0; i < this.sel.ranges.length; i++)
+ dup[i] = code;
+ this.replaceSelections(dup, collapse, origin || "+input");
+ },
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
+ var changes = [], sel = this.sel;
+ for (var i = 0; i < sel.ranges.length; i++) {
+ var range = sel.ranges[i];
+ changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
+ }
+ var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
+ for (var i = changes.length - 1; i >= 0; i--)
+ makeChange(this, changes[i]);
+ if (newSel) setSelectionReplaceHistory(this, newSel);
+ else if (this.cm) ensureCursorVisible(this.cm);
+ }),
+ undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
+ redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
+ undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
+ redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
+
+ setExtending: function(val) {this.extend = val;},
+ getExtending: function() {return this.extend;},
+
+ historySize: function() {
+ var hist = this.history, done = 0, undone = 0;
+ for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
+ for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
+ return {undo: done, redo: undone};
+ },
+ clearHistory: function() {this.history = new History(this.history.maxGeneration);},
+
+ markClean: function() {
+ this.cleanGeneration = this.changeGeneration(true);
+ },
+ changeGeneration: function(forceSplit) {
+ if (forceSplit)
+ this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
+ return this.history.generation;
+ },
+ isClean: function (gen) {
+ return this.history.generation == (gen || this.cleanGeneration);
+ },
+
+ getHistory: function() {
+ return {done: copyHistoryArray(this.history.done),
+ undone: copyHistoryArray(this.history.undone)};
+ },
+ setHistory: function(histData) {
+ var hist = this.history = new History(this.history.maxGeneration);
+ hist.done = copyHistoryArray(histData.done.slice(0), null, true);
+ hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
+ },
+
+ addLineClass: docMethodOp(function(handle, where, cls) {
+ return changeLine(this, handle, "class", function(line) {
+ var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
+ if (!line[prop]) line[prop] = cls;
+ else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
+ else line[prop] += " " + cls;
+ return true;
+ });
+ }),
+ removeLineClass: docMethodOp(function(handle, where, cls) {
+ return changeLine(this, handle, "class", function(line) {
+ var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
+ var cur = line[prop];
+ if (!cur) return false;
+ else if (cls == null) line[prop] = null;
+ else {
+ var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
+ if (!found) return false;
+ var end = found.index + found[0].length;
+ line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
+ }
+ return true;
+ });
+ }),
+
+ markText: function(from, to, options) {
+ return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
+ },
+ setBookmark: function(pos, options) {
+ var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
+ insertLeft: options && options.insertLeft,
+ clearWhenEmpty: false, shared: options && options.shared};
+ pos = clipPos(this, pos);
+ return markText(this, pos, pos, realOpts, "bookmark");
+ },
+ findMarksAt: function(pos) {
+ pos = clipPos(this, pos);
+ var markers = [], spans = getLine(this, pos.line).markedSpans;
+ if (spans) for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if ((span.from == null || span.from <= pos.ch) &&
+ (span.to == null || span.to >= pos.ch))
+ markers.push(span.marker.parent || span.marker);
+ }
+ return markers;
+ },
+ findMarks: function(from, to, filter) {
+ from = clipPos(this, from); to = clipPos(this, to);
+ var found = [], lineNo = from.line;
+ this.iter(from.line, to.line + 1, function(line) {
+ var spans = line.markedSpans;
+ if (spans) for (var i = 0; i < spans.length; i++) {
+ var span = spans[i];
+ if (!(lineNo == from.line && from.ch > span.to ||
+ span.from == null && lineNo != from.line||
+ lineNo == to.line && span.from > to.ch) &&
+ (!filter || filter(span.marker)))
+ found.push(span.marker.parent || span.marker);
+ }
+ ++lineNo;
+ });
+ return found;
+ },
+ getAllMarks: function() {
+ var markers = [];
+ this.iter(function(line) {
+ var sps = line.markedSpans;
+ if (sps) for (var i = 0; i < sps.length; ++i)
+ if (sps[i].from != null) markers.push(sps[i].marker);
+ });
+ return markers;
+ },
+
+ posFromIndex: function(off) {
+ var ch, lineNo = this.first;
+ this.iter(function(line) {
+ var sz = line.text.length + 1;
+ if (sz > off) { ch = off; return true; }
+ off -= sz;
+ ++lineNo;
+ });
+ return clipPos(this, Pos(lineNo, ch));
+ },
+ indexFromPos: function (coords) {
+ coords = clipPos(this, coords);
+ var index = coords.ch;
+ if (coords.line < this.first || coords.ch < 0) return 0;
+ this.iter(this.first, coords.line, function (line) {
+ index += line.text.length + 1;
+ });
+ return index;
+ },
+
+ copy: function(copyHistory) {
+ var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
+ doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
+ doc.sel = this.sel;
+ doc.extend = false;
+ if (copyHistory) {
+ doc.history.undoDepth = this.history.undoDepth;
+ doc.setHistory(this.getHistory());
+ }
+ return doc;
+ },
+
+ linkedDoc: function(options) {
+ if (!options) options = {};
+ var from = this.first, to = this.first + this.size;
+ if (options.from != null && options.from > from) from = options.from;
+ if (options.to != null && options.to < to) to = options.to;
+ var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
+ if (options.sharedHist) copy.history = this.history;
+ (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
+ copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
+ copySharedMarkers(copy, findSharedMarkers(this));
+ return copy;
+ },
+ unlinkDoc: function(other) {
+ if (other instanceof CodeMirror) other = other.doc;
+ if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
+ var link = this.linked[i];
+ if (link.doc != other) continue;
+ this.linked.splice(i, 1);
+ other.unlinkDoc(this);
+ detachSharedMarkers(findSharedMarkers(this));
+ break;
+ }
+ // If the histories were shared, split them again
+ if (other.history == this.history) {
+ var splitIds = [other.id];
+ linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
+ other.history = new History(null);
+ other.history.done = copyHistoryArray(this.history.done, splitIds);
+ other.history.undone = copyHistoryArray(this.history.undone, splitIds);
+ }
+ },
+ iterLinkedDocs: function(f) {linkedDocs(this, f);},
+
+ getMode: function() {return this.mode;},
+ getEditor: function() {return this.cm;}
+ });
+
+ // Public alias.
+ Doc.prototype.eachLine = Doc.prototype.iter;
+
+ // Set up methods on CodeMirror's prototype to redirect to the editor's document.
+ var dontDelegate = "iter insert remove copy getEditor".split(" ");
+ for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
+ CodeMirror.prototype[prop] = (function(method) {
+ return function() {return method.apply(this.doc, arguments);};
+ })(Doc.prototype[prop]);
+
+ eventMixin(Doc);
+
+ // Call f for all linked documents.
+ function linkedDocs(doc, f, sharedHistOnly) {
+ function propagate(doc, skip, sharedHist) {
+ if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
+ var rel = doc.linked[i];
+ if (rel.doc == skip) continue;
+ var shared = sharedHist && rel.sharedHist;
+ if (sharedHistOnly && !shared) continue;
+ f(rel.doc, shared);
+ propagate(rel.doc, doc, shared);
+ }
+ }
+ propagate(doc, null, true);
+ }
+
+ // Attach a document to an editor.
+ function attachDoc(cm, doc) {
+ if (doc.cm) throw new Error("This document is already in use.");
+ cm.doc = doc;
+ doc.cm = cm;
+ estimateLineHeights(cm);
+ loadMode(cm);
+ if (!cm.options.lineWrapping) findMaxLine(cm);
+ cm.options.mode = doc.modeOption;
+ regChange(cm);
+ }
+
+ // LINE UTILITIES
+
+ // Find the line object corresponding to the given line number.
+ function getLine(doc, n) {
+ n -= doc.first;
+ if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
+ for (var chunk = doc; !chunk.lines;) {
+ for (var i = 0;; ++i) {
+ var child = chunk.children[i], sz = child.chunkSize();
+ if (n < sz) { chunk = child; break; }
+ n -= sz;
+ }
+ }
+ return chunk.lines[n];
+ }
+
+ // Get the part of a document between two positions, as an array of
+ // strings.
+ function getBetween(doc, start, end) {
+ var out = [], n = start.line;
+ doc.iter(start.line, end.line + 1, function(line) {
+ var text = line.text;
+ if (n == end.line) text = text.slice(0, end.ch);
+ if (n == start.line) text = text.slice(start.ch);
+ out.push(text);
+ ++n;
+ });
+ return out;
+ }
+ // Get the lines between from and to, as array of strings.
+ function getLines(doc, from, to) {
+ var out = [];
+ doc.iter(from, to, function(line) { out.push(line.text); });
+ return out;
+ }
+
+ // Update the height of a line, propagating the height change
+ // upwards to parent nodes.
+ function updateLineHeight(line, height) {
+ var diff = height - line.height;
+ if (diff) for (var n = line; n; n = n.parent) n.height += diff;
+ }
+
+ // Given a line object, find its line number by walking up through
+ // its parent links.
+ function lineNo(line) {
+ if (line.parent == null) return null;
+ var cur = line.parent, no = indexOf(cur.lines, line);
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
+ for (var i = 0;; ++i) {
+ if (chunk.children[i] == cur) break;
+ no += chunk.children[i].chunkSize();
+ }
+ }
+ return no + cur.first;
+ }
+
+ // Find the line at the given vertical position, using the height
+ // information in the document tree.
+ function lineAtHeight(chunk, h) {
+ var n = chunk.first;
+ outer: do {
+ for (var i = 0; i < chunk.children.length; ++i) {
+ var child = chunk.children[i], ch = child.height;
+ if (h < ch) { chunk = child; continue outer; }
+ h -= ch;
+ n += child.chunkSize();
+ }
+ return n;
+ } while (!chunk.lines);
+ for (var i = 0; i < chunk.lines.length; ++i) {
+ var line = chunk.lines[i], lh = line.height;
+ if (h < lh) break;
+ h -= lh;
+ }
+ return n + i;
+ }
+
+
+ // Find the height above the given line.
+ function heightAtLine(lineObj) {
+ lineObj = visualLine(lineObj);
+
+ var h = 0, chunk = lineObj.parent;
+ for (var i = 0; i < chunk.lines.length; ++i) {
+ var line = chunk.lines[i];
+ if (line == lineObj) break;
+ else h += line.height;
+ }
+ for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
+ for (var i = 0; i < p.children.length; ++i) {
+ var cur = p.children[i];
+ if (cur == chunk) break;
+ else h += cur.height;
+ }
+ }
+ return h;
+ }
+
+ // Get the bidi ordering for the given line (and cache it). Returns
+ // false for lines that are fully left-to-right, and an array of
+ // BidiSpan objects otherwise.
+ function getOrder(line) {
+ var order = line.order;
+ if (order == null) order = line.order = bidiOrdering(line.text);
+ return order;
+ }
+
+ // HISTORY
+
+ function History(startGen) {
+ // Arrays of change events and selections. Doing something adds an
+ // event to done and clears undo. Undoing moves events from done
+ // to undone, redoing moves them in the other direction.
+ this.done = []; this.undone = [];
+ this.undoDepth = Infinity;
+ // Used to track when changes can be merged into a single undo
+ // event
+ this.lastModTime = this.lastSelTime = 0;
+ this.lastOp = this.lastSelOp = null;
+ this.lastOrigin = this.lastSelOrigin = null;
+ // Used by the isClean() method
+ this.generation = this.maxGeneration = startGen || 1;
+ }
+
+ // Create a history change event from an updateDoc-style change
+ // object.
+ function historyChangeFromChange(doc, change) {
+ var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
+ attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
+ linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
+ return histChange;
+ }
+
+ // Pop all selection events off the end of a history array. Stop at
+ // a change event.
+ function clearSelectionEvents(array) {
+ while (array.length) {
+ var last = lst(array);
+ if (last.ranges) array.pop();
+ else break;
+ }
+ }
+
+ // Find the top change event in the history. Pop off selection
+ // events that are in the way.
+ function lastChangeEvent(hist, force) {
+ if (force) {
+ clearSelectionEvents(hist.done);
+ return lst(hist.done);
+ } else if (hist.done.length && !lst(hist.done).ranges) {
+ return lst(hist.done);
+ } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
+ hist.done.pop();
+ return lst(hist.done);
+ }
+ }
+
+ // Register a change in the history. Merges changes that are within
+ // a single operation, ore are close together with an origin that
+ // allows merging (starting with "+") into a single event.
+ function addChangeToHistory(doc, change, selAfter, opId) {
+ var hist = doc.history;
+ hist.undone.length = 0;
+ var time = +new Date, cur;
+
+ if ((hist.lastOp == opId ||
+ hist.lastOrigin == change.origin && change.origin &&
+ ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
+ change.origin.charAt(0) == "*")) &&
+ (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
+ // Merge this change into the last event
+ var last = lst(cur.changes);
+ if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
+ // Optimized case for simple insertion -- don't want to add
+ // new changesets for every character typed
+ last.to = changeEnd(change);
+ } else {
+ // Add new sub-event
+ cur.changes.push(historyChangeFromChange(doc, change));
+ }
+ } else {
+ // Can not be merged, start a new event.
+ var before = lst(hist.done);
+ if (!before || !before.ranges)
+ pushSelectionToHistory(doc.sel, hist.done);
+ cur = {changes: [historyChangeFromChange(doc, change)],
+ generation: hist.generation};
+ hist.done.push(cur);
+ while (hist.done.length > hist.undoDepth) {
+ hist.done.shift();
+ if (!hist.done[0].ranges) hist.done.shift();
+ }
+ }
+ hist.done.push(selAfter);
+ hist.generation = ++hist.maxGeneration;
+ hist.lastModTime = hist.lastSelTime = time;
+ hist.lastOp = hist.lastSelOp = opId;
+ hist.lastOrigin = hist.lastSelOrigin = change.origin;
+
+ if (!last) signal(doc, "historyAdded");
+ }
+
+ function selectionEventCanBeMerged(doc, origin, prev, sel) {
+ var ch = origin.charAt(0);
+ return ch == "*" ||
+ ch == "+" &&
+ prev.ranges.length == sel.ranges.length &&
+ prev.somethingSelected() == sel.somethingSelected() &&
+ new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
+ }
+
+ // Called whenever the selection changes, sets the new selection as
+ // the pending selection in the history, and pushes the old pending
+ // selection into the 'done' array when it was significantly
+ // different (in number of selected ranges, emptiness, or time).
+ function addSelectionToHistory(doc, sel, opId, options) {
+ var hist = doc.history, origin = options && options.origin;
+
+ // A new event is started when the previous origin does not match
+ // the current, or the origins don't allow matching. Origins
+ // starting with * are always merged, those starting with + are
+ // merged when similar and close together in time.
+ if (opId == hist.lastSelOp ||
+ (origin && hist.lastSelOrigin == origin &&
+ (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
+ selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
+ hist.done[hist.done.length - 1] = sel;
+ else
+ pushSelectionToHistory(sel, hist.done);
+
+ hist.lastSelTime = +new Date;
+ hist.lastSelOrigin = origin;
+ hist.lastSelOp = opId;
+ if (options && options.clearRedo !== false)
+ clearSelectionEvents(hist.undone);
+ }
+
+ function pushSelectionToHistory(sel, dest) {
+ var top = lst(dest);
+ if (!(top && top.ranges && top.equals(sel)))
+ dest.push(sel);
+ }
+
+ // Used to store marked span information in the history.
+ function attachLocalSpans(doc, change, from, to) {
+ var existing = change["spans_" + doc.id], n = 0;
+ doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
+ if (line.markedSpans)
+ (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
+ ++n;
+ });
+ }
+
+ // When un/re-doing restores text containing marked spans, those
+ // that have been explicitly cleared should not be restored.
+ function removeClearedSpans(spans) {
+ if (!spans) return null;
+ for (var i = 0, out; i < spans.length; ++i) {
+ if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
+ else if (out) out.push(spans[i]);
+ }
+ return !out ? spans : out.length ? out : null;
+ }
+
+ // Retrieve and filter the old marked spans stored in a change event.
+ function getOldSpans(doc, change) {
+ var found = change["spans_" + doc.id];
+ if (!found) return null;
+ for (var i = 0, nw = []; i < change.text.length; ++i)
+ nw.push(removeClearedSpans(found[i]));
+ return nw;
+ }
+
+ // Used both to provide a JSON-safe object in .getHistory, and, when
+ // detaching a document, to split the history in two
+ function copyHistoryArray(events, newGroup, instantiateSel) {
+ for (var i = 0, copy = []; i < events.length; ++i) {
+ var event = events[i];
+ if (event.ranges) {
+ copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
+ continue;
+ }
+ var changes = event.changes, newChanges = [];
+ copy.push({changes: newChanges});
+ for (var j = 0; j < changes.length; ++j) {
+ var change = changes[j], m;
+ newChanges.push({from: change.from, to: change.to, text: change.text});
+ if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
+ if (indexOf(newGroup, Number(m[1])) > -1) {
+ lst(newChanges)[prop] = change[prop];
+ delete change[prop];
+ }
+ }
+ }
+ }
+ return copy;
+ }
+
+ // Rebasing/resetting history to deal with externally-sourced changes
+
+ function rebaseHistSelSingle(pos, from, to, diff) {
+ if (to < pos.line) {
+ pos.line += diff;
+ } else if (from < pos.line) {
+ pos.line = from;
+ pos.ch = 0;
+ }
+ }
+
+ // Tries to rebase an array of history events given a change in the
+ // document. If the change touches the same lines as the event, the
+ // event, and everything 'behind' it, is discarded. If the change is
+ // before the event, the event's positions are updated. Uses a
+ // copy-on-write scheme for the positions, to avoid having to
+ // reallocate them all on every rebase, but also avoid problems with
+ // shared position objects being unsafely updated.
+ function rebaseHistArray(array, from, to, diff) {
+ for (var i = 0; i < array.length; ++i) {
+ var sub = array[i], ok = true;
+ if (sub.ranges) {
+ if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
+ for (var j = 0; j < sub.ranges.length; j++) {
+ rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
+ rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
+ }
+ continue;
+ }
+ for (var j = 0; j < sub.changes.length; ++j) {
+ var cur = sub.changes[j];
+ if (to < cur.from.line) {
+ cur.from = Pos(cur.from.line + diff, cur.from.ch);
+ cur.to = Pos(cur.to.line + diff, cur.to.ch);
+ } else if (from <= cur.to.line) {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok) {
+ array.splice(0, i + 1);
+ i = 0;
+ }
+ }
+ }
+
+ function rebaseHist(hist, change) {
+ var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
+ rebaseHistArray(hist.done, from, to, diff);
+ rebaseHistArray(hist.undone, from, to, diff);
+ }
+
+ // EVENT UTILITIES
+
+ // Due to the fact that we still support jurassic IE versions, some
+ // compatibility wrappers are needed.
+
+ var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
+ if (e.preventDefault) e.preventDefault();
+ else e.returnValue = false;
+ };
+ var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
+ if (e.stopPropagation) e.stopPropagation();
+ else e.cancelBubble = true;
+ };
+ function e_defaultPrevented(e) {
+ return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
+ }
+ var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
+
+ function e_target(e) {return e.target || e.srcElement;}
+ function e_button(e) {
+ var b = e.which;
+ if (b == null) {
+ if (e.button & 1) b = 1;
+ else if (e.button & 2) b = 3;
+ else if (e.button & 4) b = 2;
+ }
+ if (mac && e.ctrlKey && b == 1) b = 3;
+ return b;
+ }
+
+ // EVENT HANDLING
+
+ // Lightweight event framework. on/off also work on DOM nodes,
+ // registering native DOM handlers.
+
+ var on = CodeMirror.on = function(emitter, type, f) {
+ if (emitter.addEventListener)
+ emitter.addEventListener(type, f, false);
+ else if (emitter.attachEvent)
+ emitter.attachEvent("on" + type, f);
+ else {
+ var map = emitter._handlers || (emitter._handlers = {});
+ var arr = map[type] || (map[type] = []);
+ arr.push(f);
+ }
+ };
+
+ var off = CodeMirror.off = function(emitter, type, f) {
+ if (emitter.removeEventListener)
+ emitter.removeEventListener(type, f, false);
+ else if (emitter.detachEvent)
+ emitter.detachEvent("on" + type, f);
+ else {
+ var arr = emitter._handlers && emitter._handlers[type];
+ if (!arr) return;
+ for (var i = 0; i < arr.length; ++i)
+ if (arr[i] == f) { arr.splice(i, 1); break; }
+ }
+ };
+
+ var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
+ var arr = emitter._handlers && emitter._handlers[type];
+ if (!arr) return;
+ var args = Array.prototype.slice.call(arguments, 2);
+ for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
+ };
+
+ var orphanDelayedCallbacks = null;
+
+ // Often, we want to signal events at a point where we are in the
+ // middle of some work, but don't want the handler to start calling
+ // other methods on the editor, which might be in an inconsistent
+ // state or simply not expect any other events to happen.
+ // signalLater looks whether there are any handlers, and schedules
+ // them to be executed when the last operation ends, or, if no
+ // operation is active, when a timeout fires.
+ function signalLater(emitter, type /*, values...*/) {
+ var arr = emitter._handlers && emitter._handlers[type];
+ if (!arr) return;
+ var args = Array.prototype.slice.call(arguments, 2), list;
+ if (operationGroup) {
+ list = operationGroup.delayedCallbacks;
+ } else if (orphanDelayedCallbacks) {
+ list = orphanDelayedCallbacks;
+ } else {
+ list = orphanDelayedCallbacks = [];
+ setTimeout(fireOrphanDelayed, 0);
+ }
+ function bnd(f) {return function(){f.apply(null, args);};};
+ for (var i = 0; i < arr.length; ++i)
+ list.push(bnd(arr[i]));
+ }
+
+ function fireOrphanDelayed() {
+ var delayed = orphanDelayedCallbacks;
+ orphanDelayedCallbacks = null;
+ for (var i = 0; i < delayed.length; ++i) delayed[i]();
+ }
+
+ // The DOM events that CodeMirror handles can be overridden by
+ // registering a (non-DOM) handler on the editor for the event name,
+ // and preventDefault-ing the event in that handler.
+ function signalDOMEvent(cm, e, override) {
+ signal(cm, override || e.type, cm, e);
+ return e_defaultPrevented(e) || e.codemirrorIgnore;
+ }
+
+ function signalCursorActivity(cm) {
+ var arr = cm._handlers && cm._handlers.cursorActivity;
+ if (!arr) return;
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
+ for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
+ set.push(arr[i]);
+ }
+
+ function hasHandler(emitter, type) {
+ var arr = emitter._handlers && emitter._handlers[type];
+ return arr && arr.length > 0;
+ }
+
+ // Add on and off methods to a constructor's prototype, to make
+ // registering events on such objects more convenient.
+ function eventMixin(ctor) {
+ ctor.prototype.on = function(type, f) {on(this, type, f);};
+ ctor.prototype.off = function(type, f) {off(this, type, f);};
+ }
+
+ // MISC UTILITIES
+
+ // Number of pixels added to scroller and sizer to hide scrollbar
+ var scrollerCutOff = 30;
+
+ // Returned or thrown by various protocols to signal 'I'm not
+ // handling this'.
+ var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
+
+ // Reused option objects for setSelection & friends
+ var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
+
+ function Delayed() {this.id = null;}
+ Delayed.prototype.set = function(ms, f) {
+ clearTimeout(this.id);
+ this.id = setTimeout(f, ms);
+ };
+
+ // Counts the column offset in a string, taking tabs into account.
+ // Used mostly to find indentation.
+ var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
+ if (end == null) {
+ end = string.search(/[^\s\u00a0]/);
+ if (end == -1) end = string.length;
+ }
+ for (var i = startIndex || 0, n = startValue || 0;;) {
+ var nextTab = string.indexOf("\t", i);
+ if (nextTab < 0 || nextTab >= end)
+ return n + (end - i);
+ n += nextTab - i;
+ n += tabSize - (n % tabSize);
+ i = nextTab + 1;
+ }
+ };
+
+ // The inverse of countColumn -- find the offset that corresponds to
+ // a particular column.
+ function findColumn(string, goal, tabSize) {
+ for (var pos = 0, col = 0;;) {
+ var nextTab = string.indexOf("\t", pos);
+ if (nextTab == -1) nextTab = string.length;
+ var skipped = nextTab - pos;
+ if (nextTab == string.length || col + skipped >= goal)
+ return pos + Math.min(skipped, goal - col);
+ col += nextTab - pos;
+ col += tabSize - (col % tabSize);
+ pos = nextTab + 1;
+ if (col >= goal) return pos;
+ }
+ }
+
+ var spaceStrs = [""];
+ function spaceStr(n) {
+ while (spaceStrs.length <= n)
+ spaceStrs.push(lst(spaceStrs) + " ");
+ return spaceStrs[n];
+ }
+
+ function lst(arr) { return arr[arr.length-1]; }
+
+ var selectInput = function(node) { node.select(); };
+ if (ios) // Mobile Safari apparently has a bug where select() is broken.
+ selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
+ else if (ie) // Suppress mysterious IE10 errors
+ selectInput = function(node) { try { node.select(); } catch(_e) {} };
+
+ function indexOf(array, elt) {
+ for (var i = 0; i < array.length; ++i)
+ if (array[i] == elt) return i;
+ return -1;
+ }
+ if ([].indexOf) indexOf = function(array, elt) { return array.indexOf(elt); };
+ function map(array, f) {
+ var out = [];
+ for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
+ return out;
+ }
+ if ([].map) map = function(array, f) { return array.map(f); };
+
+ function createObj(base, props) {
+ var inst;
+ if (Object.create) {
+ inst = Object.create(base);
+ } else {
+ var ctor = function() {};
+ ctor.prototype = base;
+ inst = new ctor();
+ }
+ if (props) copyObj(props, inst);
+ return inst;
+ };
+
+ function copyObj(obj, target, overwrite) {
+ if (!target) target = {};
+ for (var prop in obj)
+ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
+ target[prop] = obj[prop];
+ return target;
+ }
+
+ function bind(f) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function(){return f.apply(null, args);};
+ }
+
+ var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
+ var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
+ return /\w/.test(ch) || ch > "\x80" &&
+ (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
+ };
+ function isWordChar(ch, helper) {
+ if (!helper) return isWordCharBasic(ch);
+ if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
+ return helper.test(ch);
+ }
+
+ function isEmpty(obj) {
+ for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
+ return true;
+ }
+
+ // Extending unicode characters. A series of a non-extending char +
+ // any number of extending chars is treated as a single unit as far
+ // as editing and measuring is concerned. This is not fully correct,
+ // since some scripts/fonts/browsers also treat other configurations
+ // of code points as a group.
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
+
+ // DOM UTILITIES
+
+ function elt(tag, content, className, style) {
+ var e = document.createElement(tag);
+ if (className) e.className = className;
+ if (style) e.style.cssText = style;
+ if (typeof content == "string") e.appendChild(document.createTextNode(content));
+ else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
+ return e;
+ }
+
+ var range;
+ if (document.createRange) range = function(node, start, end) {
+ var r = document.createRange();
+ r.setEnd(node, end);
+ r.setStart(node, start);
+ return r;
+ };
+ else range = function(node, start, end) {
+ var r = document.body.createTextRange();
+ r.moveToElementText(node.parentNode);
+ r.collapse(true);
+ r.moveEnd("character", end);
+ r.moveStart("character", start);
+ return r;
+ };
+
+ function removeChildren(e) {
+ for (var count = e.childNodes.length; count > 0; --count)
+ e.removeChild(e.firstChild);
+ return e;
+ }
+
+ function removeChildrenAndAdd(parent, e) {
+ return removeChildren(parent).appendChild(e);
+ }
+
+ function contains(parent, child) {
+ if (parent.contains)
+ return parent.contains(child);
+ while (child = child.parentNode)
+ if (child == parent) return true;
+ }
+
+ function activeElt() { return document.activeElement; }
+ // Older versions of IE throws unspecified error when touching
+ // document.activeElement in some cases (during loading, in iframe)
+ if (ie && ie_version < 11) activeElt = function() {
+ try { return document.activeElement; }
+ catch(e) { return document.body; }
+ };
+
+ function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
+ function rmClass(node, cls) {
+ var test = classTest(cls);
+ if (test.test(node.className)) node.className = node.className.replace(test, "");
+ }
+ function addClass(node, cls) {
+ if (!classTest(cls).test(node.className)) node.className += " " + cls;
+ }
+ function joinClasses(a, b) {
+ var as = a.split(" ");
+ for (var i = 0; i < as.length; i++)
+ if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
+ return b;
+ }
+
+ // WINDOW-WIDE EVENTS
+
+ // These must be handled carefully, because naively registering a
+ // handler for each editor will cause the editors to never be
+ // garbage collected.
+
+ function forEachCodeMirror(f) {
+ if (!document.body.getElementsByClassName) return;
+ var byClass = document.body.getElementsByClassName("CodeMirror");
+ for (var i = 0; i < byClass.length; i++) {
+ var cm = byClass[i].CodeMirror;
+ if (cm) f(cm);
+ }
+ }
+
+ var globalsRegistered = false;
+ function ensureGlobalHandlers() {
+ if (globalsRegistered) return;
+ registerGlobalHandlers();
+ globalsRegistered = true;
+ }
+ function registerGlobalHandlers() {
+ // When the window resizes, we need to refresh active editors.
+ var resizeTimer;
+ on(window, "resize", function() {
+ if (resizeTimer == null) resizeTimer = setTimeout(function() {
+ resizeTimer = null;
+ knownScrollbarWidth = null;
+ forEachCodeMirror(onResize);
+ }, 100);
+ });
+ // When the window loses focus, we want to show the editor as blurred
+ on(window, "blur", function() {
+ forEachCodeMirror(onBlur);
+ });
+ }
+
+ // FEATURE DETECTION
+
+ // Detect drag-and-drop
+ var dragAndDrop = function() {
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
+ // couldn't get it to work yet.
+ if (ie && ie_version < 9) return false;
+ var div = elt('div');
+ return "draggable" in div || "dragDrop" in div;
+ }();
+
+ var knownScrollbarWidth;
+ function scrollbarWidth(measure) {
+ if (knownScrollbarWidth != null) return knownScrollbarWidth;
+ var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
+ removeChildrenAndAdd(measure, test);
+ if (test.offsetWidth)
+ knownScrollbarWidth = test.offsetHeight - test.clientHeight;
+ return knownScrollbarWidth || 0;
+ }
+
+ var zwspSupported;
+ function zeroWidthElement(measure) {
+ if (zwspSupported == null) {
+ var test = elt("span", "\u200b");
+ removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
+ if (measure.firstChild.offsetHeight != 0)
+ zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
+ }
+ if (zwspSupported) return elt("span", "\u200b");
+ else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
+ }
+
+ // Feature-detect IE's crummy client rect reporting for bidi text
+ var badBidiRects;
+ function hasBadBidiRects(measure) {
+ if (badBidiRects != null) return badBidiRects;
+ var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
+ var r0 = range(txt, 0, 1).getBoundingClientRect();
+ if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
+ var r1 = range(txt, 1, 2).getBoundingClientRect();
+ return badBidiRects = (r1.right - r0.right < 3);
+ }
+
+ // See if "".split is the broken IE version, if so, provide an
+ // alternative way to split lines.
+ var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
+ var pos = 0, result = [], l = string.length;
+ while (pos <= l) {
+ var nl = string.indexOf("\n", pos);
+ if (nl == -1) nl = string.length;
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
+ var rt = line.indexOf("\r");
+ if (rt != -1) {
+ result.push(line.slice(0, rt));
+ pos += rt + 1;
+ } else {
+ result.push(line);
+ pos = nl + 1;
+ }
+ }
+ return result;
+ } : function(string){return string.split(/\r\n?|\n/);};
+
+ var hasSelection = window.getSelection ? function(te) {
+ try { return te.selectionStart != te.selectionEnd; }
+ catch(e) { return false; }
+ } : function(te) {
+ try {var range = te.ownerDocument.selection.createRange();}
+ catch(e) {}
+ if (!range || range.parentElement() != te) return false;
+ return range.compareEndPoints("StartToEnd", range) != 0;
+ };
+
+ var hasCopyEvent = (function() {
+ var e = elt("div");
+ if ("oncopy" in e) return true;
+ e.setAttribute("oncopy", "return;");
+ return typeof e.oncopy == "function";
+ })();
+
+ var badZoomedRects = null;
+ function hasBadZoomedRects(measure) {
+ if (badZoomedRects != null) return badZoomedRects;
+ var node = removeChildrenAndAdd(measure, elt("span", "x"));
+ var normal = node.getBoundingClientRect();
+ var fromRange = range(node, 0, 1).getBoundingClientRect();
+ return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
+ }
+
+ // KEY NAMES
+
+ var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
+ CodeMirror.keyNames = keyNames;
+ (function() {
+ // Number keys
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
+ // Alphabetic keys
+ for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
+ // Function keys
+ for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
+ })();
+
+ // BIDI HELPERS
+
+ function iterateBidiSections(order, from, to, f) {
+ if (!order) return f(from, to, "ltr");
+ var found = false;
+ for (var i = 0; i < order.length; ++i) {
+ var part = order[i];
+ if (part.from < to && part.to > from || from == to && part.to == from) {
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
+ found = true;
+ }
+ }
+ if (!found) f(from, to, "ltr");
+ }
+
+ function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
+ function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
+
+ function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
+ function lineRight(line) {
+ var order = getOrder(line);
+ if (!order) return line.text.length;
+ return bidiRight(lst(order));
+ }
+
+ function lineStart(cm, lineN) {
+ var line = getLine(cm.doc, lineN);
+ var visual = visualLine(line);
+ if (visual != line) lineN = lineNo(visual);
+ var order = getOrder(visual);
+ var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
+ return Pos(lineN, ch);
+ }
+ function lineEnd(cm, lineN) {
+ var merged, line = getLine(cm.doc, lineN);
+ while (merged = collapsedSpanAtEnd(line)) {
+ line = merged.find(1, true).line;
+ lineN = null;
+ }
+ var order = getOrder(line);
+ var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
+ return Pos(lineN == null ? lineNo(line) : lineN, ch);
+ }
+ function lineStartSmart(cm, pos) {
+ var start = lineStart(cm, pos.line);
+ var line = getLine(cm.doc, start.line);
+ var order = getOrder(line);
+ if (!order || order[0].level == 0) {
+ var firstNonWS = Math.max(0, line.text.search(/\S/));
+ var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
+ return Pos(start.line, inWS ? 0 : firstNonWS);
+ }
+ return start;
+ }
+
+ function compareBidiLevel(order, a, b) {
+ var linedir = order[0].level;
+ if (a == linedir) return true;
+ if (b == linedir) return false;
+ return a < b;
+ }
+ var bidiOther;
+ function getBidiPartAt(order, pos) {
+ bidiOther = null;
+ for (var i = 0, found; i < order.length; ++i) {
+ var cur = order[i];
+ if (cur.from < pos && cur.to > pos) return i;
+ if ((cur.from == pos || cur.to == pos)) {
+ if (found == null) {
+ found = i;
+ } else if (compareBidiLevel(order, cur.level, order[found].level)) {
+ if (cur.from != cur.to) bidiOther = found;
+ return i;
+ } else {
+ if (cur.from != cur.to) bidiOther = i;
+ return found;
+ }
+ }
+ }
+ return found;
+ }
+
+ function moveInLine(line, pos, dir, byUnit) {
+ if (!byUnit) return pos + dir;
+ do pos += dir;
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
+ return pos;
+ }
+
+ // This is needed in order to move 'visually' through bi-directional
+ // text -- i.e., pressing left should make the cursor go left, even
+ // when in RTL text. The tricky part is the 'jumps', where RTL and
+ // LTR text touch each other. This often requires the cursor offset
+ // to move more than one unit, in order to visually move one unit.
+ function moveVisually(line, start, dir, byUnit) {
+ var bidi = getOrder(line);
+ if (!bidi) return moveLogically(line, start, dir, byUnit);
+ var pos = getBidiPartAt(bidi, start), part = bidi[pos];
+ var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
+
+ for (;;) {
+ if (target > part.from && target < part.to) return target;
+ if (target == part.from || target == part.to) {
+ if (getBidiPartAt(bidi, target) == pos) return target;
+ part = bidi[pos += dir];
+ return (dir > 0) == part.level % 2 ? part.to : part.from;
+ } else {
+ part = bidi[pos += dir];
+ if (!part) return null;
+ if ((dir > 0) == part.level % 2)
+ target = moveInLine(line, part.to, -1, byUnit);
+ else
+ target = moveInLine(line, part.from, 1, byUnit);
+ }
+ }
+ }
+
+ function moveLogically(line, start, dir, byUnit) {
+ var target = start + dir;
+ if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
+ return target < 0 || target > line.text.length ? null : target;
+ }
+
+ // Bidirectional ordering algorithm
+ // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
+ // that this (partially) implements.
+
+ // One-char codes used for character types:
+ // L (L): Left-to-Right
+ // R (R): Right-to-Left
+ // r (AL): Right-to-Left Arabic
+ // 1 (EN): European Number
+ // + (ES): European Number Separator
+ // % (ET): European Number Terminator
+ // n (AN): Arabic Number
+ // , (CS): Common Number Separator
+ // m (NSM): Non-Spacing Mark
+ // b (BN): Boundary Neutral
+ // s (B): Paragraph Separator
+ // t (S): Segment Separator
+ // w (WS): Whitespace
+ // N (ON): Other Neutrals
+
+ // Returns null if characters are ordered as they appear
+ // (left-to-right), or an array of sections ({from, to, level}
+ // objects) in the order in which they occur visually.
+ var bidiOrdering = (function() {
+ // Character types for codepoints 0 to 0xff
+ var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
+ // Character types for codepoints 0x600 to 0x6ff
+ var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
+ function charType(code) {
+ if (code <= 0xf7) return lowTypes.charAt(code);
+ else if (0x590 <= code && code <= 0x5f4) return "R";
+ else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
+ else if (0x6ee <= code && code <= 0x8ac) return "r";
+ else if (0x2000 <= code && code <= 0x200b) return "w";
+ else if (code == 0x200c) return "b";
+ else return "L";
+ }
+
+ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
+ var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
+ // Browsers seem to always treat the boundaries of block elements as being L.
+ var outerType = "L";
+
+ function BidiSpan(level, from, to) {
+ this.level = level;
+ this.from = from; this.to = to;
+ }
+
+ return function(str) {
+ if (!bidiRE.test(str)) return false;
+ var len = str.length, types = [];
+ for (var i = 0, type; i < len; ++i)
+ types.push(type = charType(str.charCodeAt(i)));
+
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
+ // change the type of the NSM to the type of the previous
+ // character. If the NSM is at the start of the level run, it will
+ // get the type of sor.
+ for (var i = 0, prev = outerType; i < len; ++i) {
+ var type = types[i];
+ if (type == "m") types[i] = prev;
+ else prev = type;
+ }
+
+ // W2. Search backwards from each instance of a European number
+ // until the first strong type (R, L, AL, or sor) is found. If an
+ // AL is found, change the type of the European number to Arabic
+ // number.
+ // W3. Change all ALs to R.
+ for (var i = 0, cur = outerType; i < len; ++i) {
+ var type = types[i];
+ if (type == "1" && cur == "r") types[i] = "n";
+ else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
+ }
+
+ // W4. A single European separator between two European numbers
+ // changes to a European number. A single common separator between
+ // two numbers of the same type changes to that type.
+ for (var i = 1, prev = types[0]; i < len - 1; ++i) {
+ var type = types[i];
+ if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
+ else if (type == "," && prev == types[i+1] &&
+ (prev == "1" || prev == "n")) types[i] = prev;
+ prev = type;
+ }
+
+ // W5. A sequence of European terminators adjacent to European
+ // numbers changes to all European numbers.
+ // W6. Otherwise, separators and terminators change to Other
+ // Neutral.
+ for (var i = 0; i < len; ++i) {
+ var type = types[i];
+ if (type == ",") types[i] = "N";
+ else if (type == "%") {
+ for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
+ var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
+ for (var j = i; j < end; ++j) types[j] = replace;
+ i = end - 1;
+ }
+ }
+
+ // W7. Search backwards from each instance of a European number
+ // until the first strong type (R, L, or sor) is found. If an L is
+ // found, then change the type of the European number to L.
+ for (var i = 0, cur = outerType; i < len; ++i) {
+ var type = types[i];
+ if (cur == "L" && type == "1") types[i] = "L";
+ else if (isStrong.test(type)) cur = type;
+ }
+
+ // N1. A sequence of neutrals takes the direction of the
+ // surrounding strong text if the text on both sides has the same
+ // direction. European and Arabic numbers act as if they were R in
+ // terms of their influence on neutrals. Start-of-level-run (sor)
+ // and end-of-level-run (eor) are used at level run boundaries.
+ // N2. Any remaining neutrals take the embedding direction.
+ for (var i = 0; i < len; ++i) {
+ if (isNeutral.test(types[i])) {
+ for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
+ var before = (i ? types[i-1] : outerType) == "L";
+ var after = (end < len ? types[end] : outerType) == "L";
+ var replace = before || after ? "L" : "R";
+ for (var j = i; j < end; ++j) types[j] = replace;
+ i = end - 1;
+ }
+ }
+
+ // Here we depart from the documented algorithm, in order to avoid
+ // building up an actual levels array. Since there are only three
+ // levels (0, 1, 2) in an implementation that doesn't take
+ // explicit embedding into account, we can build up the order on
+ // the fly, without following the level-based algorithm.
+ var order = [], m;
+ for (var i = 0; i < len;) {
+ if (countsAsLeft.test(types[i])) {
+ var start = i;
+ for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
+ order.push(new BidiSpan(0, start, i));
+ } else {
+ var pos = i, at = order.length;
+ for (++i; i < len && types[i] != "L"; ++i) {}
+ for (var j = pos; j < i;) {
+ if (countsAsNum.test(types[j])) {
+ if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
+ var nstart = j;
+ for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
+ order.splice(at, 0, new BidiSpan(2, nstart, j));
+ pos = j;
+ } else ++j;
+ }
+ if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
+ }
+ }
+ if (order[0].level == 1 && (m = str.match(/^\s+/))) {
+ order[0].from = m[0].length;
+ order.unshift(new BidiSpan(0, 0, m[0].length));
+ }
+ if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
+ lst(order).to -= m[0].length;
+ order.push(new BidiSpan(0, len - m[0].length, len));
+ }
+ if (order[0].level != lst(order).level)
+ order.push(new BidiSpan(order[0].level, len, len));
+
+ return order;
+ };
+ })();
+
+ // THE END
+
+ CodeMirror.version = "4.7.0";
+
+ return CodeMirror;
+});
diff --git a/apps/static/js/plugins/codemirror/mode/index.html b/apps/static/js/plugins/codemirror/mode/index.html
new file mode 100755
index 000000000..bb656d2a7
--- /dev/null
+++ b/apps/static/js/plugins/codemirror/mode/index.html
@@ -0,0 +1,125 @@
+
+
+CodeMirror: Language Modes
+
+
+
+
+
+
+
+Language modes
+
+This is a list of every mode in the distribution. Each mode lives
+in a subdirectory of the mode/
directory, and typically
+defines a single JavaScript file that implements the mode. Loading
+such file will make the language available to CodeMirror, through
+the mode
+option.
+
+
+
+
diff --git a/apps/static/js/plugins/codemirror/mode/meta.js b/apps/static/js/plugins/codemirror/mode/meta.js
new file mode 100755
index 000000000..cee33e542
--- /dev/null
+++ b/apps/static/js/plugins/codemirror/mode/meta.js
@@ -0,0 +1,144 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
+ mod(require("../lib/codemirror"));
+ else if (typeof define == "function" && define.amd) // AMD
+ define(["../lib/codemirror"], mod);
+ else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+ "use strict";
+
+ CodeMirror.modeInfo = [
+ {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
+ {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk"},
+ {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]},
+ {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "hpp", "h++"]},
+ {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
+ {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"]},
+ {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]},
+ {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"]},
+ {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"]},
+ {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher"},
+ {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
+ {name: "CSS", mime: "text/css", mode: "css", ext: ["css"]},
+ {name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]},
+ {name: "D", mime: "text/x-d", mode: "d", ext: ["d"]},
+ {name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]},
+ {name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]},
+ {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
+ {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
+ {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
+ {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
+ {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
+ {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
+ {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"]},
+ {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
+ {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
+ {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm"},
+ {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
+ {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy"]},
+ {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
+ {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
+ {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
+ {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
+ {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"]},
+ {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"]},
+ {name: "HTTP", mime: "message/http", mode: "http"},
+ {name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]},
+ {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
+ {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"]},
+ {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
+ mode: "javascript", ext: ["js"]},
+ {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"]},
+ {name: "JSON-LD", mime: "application/ld+json", mode: "javascript"},
+ {name: "Jinja2", mime: "null", mode: "jinja2"},
+ {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
+ {name: "Kotlin", mime: "text/x-kotlin", mode: "kotlin", ext: ["kt"]},
+ {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
+ {name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"]},
+ {name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]},
+ {name: "Markdown (GitHub-flavour)", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
+ {name: "mIRC", mime: "text/mirc", mode: "mirc"},
+ {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
+ {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
+ {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
+ {name: "MySQL", mime: "text/x-mysql", mode: "sql"},
+ {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx"},
+ {name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]},
+ {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
+ {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
+ {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
+ {name: "PEG.js", mime: "null", mode: "pegjs"},
+ {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
+ {name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "phtml"]},
+ {name: "Pig", mime: "text/x-pig", mode: "pig"},
+ {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
+ {name: "PLSQL", mime: "text/x-plsql", mode: "sql"},
+ {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"]},
+ {name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]},
+ {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
+ {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
+ {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"]},
+ {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"]},
+ {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"]},
+ {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
+ {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
+ {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
+ {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
+ {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
+ {name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"]},
+ {name: "Sieve", mime: "application/sieve", mode: "sieve"},
+ {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim"},
+ {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
+ {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
+ {name: "SmartyMixed", mime: "text/x-smarty", mode: "smartymixed"},
+ {name: "Solr", mime: "text/x-solr", mode: "solr"},
+ {name: "SPARQL", mime: "application/x-sparql-query", mode: "sparql", ext: ["sparql"]},
+ {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
+ {name: "MariaDB", mime: "text/x-mariadb", mode: "sql"},
+ {name: "sTeX", mime: "text/x-stex", mode: "stex"},
+ {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"]},
+ {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
+ {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
+ {name: "Textile", mime: "text/x-textile", mode: "textile"},
+ {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
+ {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
+ {name: "TOML", mime: "text/x-toml", mode: "toml"},
+ {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
+ {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
+ {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"]},
+ {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
+ {name: "VBScript", mime: "text/vbscript", mode: "vbscript"},
+ {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
+ {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
+ {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"]},
+ {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
+ {name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml"]},
+ {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]}
+ ];
+ // Ensure all modes have a mime property for backwards compatibility
+ for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
+ var info = CodeMirror.modeInfo[i];
+ if (info.mimes) info.mime = info.mimes[0];
+ }
+
+ CodeMirror.findModeByMIME = function(mime) {
+ for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
+ var info = CodeMirror.modeInfo[i];
+ if (info.mime == mime) return info;
+ if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
+ if (info.mimes[j] == mime) return info;
+ }
+ };
+
+ CodeMirror.findModeByExtension = function(ext) {
+ for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
+ var info = CodeMirror.modeInfo[i];
+ if (info.ext) for (var j = 0; j < info.ext.length; j++)
+ if (info.ext[j] == ext) return info;
+ }
+ };
+});
diff --git a/apps/static/js/plugins/codemirror/mode/shell/index.html b/apps/static/js/plugins/codemirror/mode/shell/index.html
new file mode 100755
index 000000000..0b56300b1
--- /dev/null
+++ b/apps/static/js/plugins/codemirror/mode/shell/index.html
@@ -0,0 +1,66 @@
+
+
+CodeMirror: Shell mode
+
+
+
+
+
+
+
+
+
+
+
+Shell mode
+
+
+
+
+
+
+MIME types defined: text/x-sh
.
+
diff --git a/apps/static/js/plugins/codemirror/mode/shell/shell.js b/apps/static/js/plugins/codemirror/mode/shell/shell.js
new file mode 100755
index 000000000..8e31f6f30
--- /dev/null
+++ b/apps/static/js/plugins/codemirror/mode/shell/shell.js
@@ -0,0 +1,138 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
+ mod(require("../../lib/codemirror"));
+ else if (typeof define == "function" && define.amd) // AMD
+ define(["../../lib/codemirror"], mod);
+ else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode('shell', function() {
+
+ var words = {};
+ function define(style, string) {
+ var split = string.split(' ');
+ for(var i = 0; i < split.length; i++) {
+ words[split[i]] = style;
+ }
+ };
+
+ // Atoms
+ define('atom', 'true false');
+
+ // Keywords
+ define('keyword', 'if then do else elif while until for in esac fi fin ' +
+ 'fil done exit set unset export function');
+
+ // Commands
+ define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' +
+ 'curl cut diff echo find gawk gcc get git grep kill killall ln ls make ' +
+ 'mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh ' +
+ 'shopt shred source sort sleep ssh start stop su sudo tee telnet top ' +
+ 'touch vi vim wall wc wget who write yes zsh');
+
+ function tokenBase(stream, state) {
+ if (stream.eatSpace()) return null;
+
+ var sol = stream.sol();
+ var ch = stream.next();
+
+ if (ch === '\\') {
+ stream.next();
+ return null;
+ }
+ if (ch === '\'' || ch === '"' || ch === '`') {
+ state.tokens.unshift(tokenString(ch));
+ return tokenize(stream, state);
+ }
+ if (ch === '#') {
+ if (sol && stream.eat('!')) {
+ stream.skipToEnd();
+ return 'meta'; // 'comment'?
+ }
+ stream.skipToEnd();
+ return 'comment';
+ }
+ if (ch === '$') {
+ state.tokens.unshift(tokenDollar);
+ return tokenize(stream, state);
+ }
+ if (ch === '+' || ch === '=') {
+ return 'operator';
+ }
+ if (ch === '-') {
+ stream.eat('-');
+ stream.eatWhile(/\w/);
+ return 'attribute';
+ }
+ if (/\d/.test(ch)) {
+ stream.eatWhile(/\d/);
+ if(stream.eol() || !/\w/.test(stream.peek())) {
+ return 'number';
+ }
+ }
+ stream.eatWhile(/[\w-]/);
+ var cur = stream.current();
+ if (stream.peek() === '=' && /\w+/.test(cur)) return 'def';
+ return words.hasOwnProperty(cur) ? words[cur] : null;
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var next, end = false, escaped = false;
+ while ((next = stream.next()) != null) {
+ if (next === quote && !escaped) {
+ end = true;
+ break;
+ }
+ if (next === '$' && !escaped && quote !== '\'') {
+ escaped = true;
+ stream.backUp(1);
+ state.tokens.unshift(tokenDollar);
+ break;
+ }
+ escaped = !escaped && next === '\\';
+ }
+ if (end || !escaped) {
+ state.tokens.shift();
+ }
+ return (quote === '`' || quote === ')' ? 'quote' : 'string');
+ };
+ };
+
+ var tokenDollar = function(stream, state) {
+ if (state.tokens.length > 1) stream.eat('$');
+ var ch = stream.next(), hungry = /\w/;
+ if (ch === '{') hungry = /[^}]/;
+ if (ch === '(') {
+ state.tokens[0] = tokenString(')');
+ return tokenize(stream, state);
+ }
+ if (!/\d/.test(ch)) {
+ stream.eatWhile(hungry);
+ stream.eat('}');
+ }
+ state.tokens.shift();
+ return 'def';
+ };
+
+ function tokenize(stream, state) {
+ return (state.tokens[0] || tokenBase) (stream, state);
+ };
+
+ return {
+ startState: function() {return {tokens:[]};},
+ token: function(stream, state) {
+ return tokenize(stream, state);
+ },
+ lineComment: '#'
+ };
+});
+
+CodeMirror.defineMIME('text/x-sh', 'shell');
+
+});
diff --git a/apps/static/js/plugins/codemirror/mode/shell/test.js b/apps/static/js/plugins/codemirror/mode/shell/test.js
new file mode 100755
index 000000000..a413b5a40
--- /dev/null
+++ b/apps/static/js/plugins/codemirror/mode/shell/test.js
@@ -0,0 +1,58 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function() {
+ var mode = CodeMirror.getMode({}, "shell");
+ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+
+ MT("var",
+ "text [def $var] text");
+ MT("varBraces",
+ "text[def ${var}]text");
+ MT("varVar",
+ "text [def $a$b] text");
+ MT("varBracesVarBraces",
+ "text[def ${a}${b}]text");
+
+ MT("singleQuotedVar",
+ "[string 'text $var text']");
+ MT("singleQuotedVarBraces",
+ "[string 'text ${var} text']");
+
+ MT("doubleQuotedVar",
+ '[string "text ][def $var][string text"]');
+ MT("doubleQuotedVarBraces",
+ '[string "text][def ${var}][string text"]');
+ MT("doubleQuotedVarPunct",
+ '[string "text ][def $@][string text"]');
+ MT("doubleQuotedVarVar",
+ '[string "][def $a$b][string "]');
+ MT("doubleQuotedVarBracesVarBraces",
+ '[string "][def ${a}${b}][string "]');
+
+ MT("notAString",
+ "text\\'text");
+ MT("escapes",
+ "outside\\'\\\"\\`\\\\[string \"inside\\`\\'\\\"\\\\`\\$notAVar\"]outside\\$\\(notASubShell\\)");
+
+ MT("subshell",
+ "[builtin echo] [quote $(whoami)] s log, stardate [quote `date`].");
+ MT("doubleQuotedSubshell",
+ "[builtin echo] [string \"][quote $(whoami)][string 's log, stardate `date`.\"]");
+
+ MT("hashbang",
+ "[meta #!/bin/bash]");
+ MT("comment",
+ "text [comment # Blurb]");
+
+ MT("numbers",
+ "[number 0] [number 1] [number 2]");
+ MT("keywords",
+ "[keyword while] [atom true]; [keyword do]",
+ " [builtin sleep] [number 3]",
+ "[keyword done]");
+ MT("options",
+ "[builtin ls] [attribute -l] [attribute --human-readable]");
+ MT("operator",
+ "[def var][operator =]value");
+})();
diff --git a/apps/static/js/plugins/xterm/addons/attach/attach.js b/apps/static/js/plugins/xterm/addons/attach/attach.js
new file mode 100644
index 000000000..73411b2cd
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/attach/attach.js
@@ -0,0 +1,105 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.attach = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;iterm;\n bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional;\n addonTerminal.__socket = socket;\n\n addonTerminal.__flushBuffer = () => {\n addonTerminal.write(addonTerminal.__attachSocketBuffer);\n addonTerminal.__attachSocketBuffer = null;\n };\n\n addonTerminal.__pushToBuffer = (data: string) => {\n if (addonTerminal.__attachSocketBuffer) {\n addonTerminal.__attachSocketBuffer += data;\n } else {\n addonTerminal.__attachSocketBuffer = data;\n setTimeout(addonTerminal.__flushBuffer, 10);\n }\n };\n\n // TODO: This should be typed but there seem to be issues importing the type\n let myTextDecoder: any;\n\n addonTerminal.__getMessage = function(ev: MessageEvent): void {\n let str: string;\n\n if (typeof ev.data === 'object') {\n if (!myTextDecoder) {\n myTextDecoder = new TextDecoder();\n }\n if (ev.data instanceof ArrayBuffer) {\n str = myTextDecoder.decode(ev.data);\n displayData(str);\n } else {\n const fileReader = new FileReader();\n\n fileReader.addEventListener('load', () => {\n str = myTextDecoder.decode(this.result);\n displayData(str);\n });\n fileReader.readAsArrayBuffer(ev.data);\n }\n } else if (typeof ev.data === 'string') {\n displayData(ev.data);\n } else {\n throw Error(`Cannot handle \"${typeof ev.data}\" websocket message.`);\n }\n };\n\n /**\n * Push data to buffer or write it in the terminal.\n * This is used as a callback for FileReader.onload.\n *\n * @param str String decoded by FileReader.\n * @param data The data of the EventMessage.\n */\n function displayData(str?: string, data?: string): void {\n if (buffered) {\n addonTerminal.__pushToBuffer(str || data);\n } else {\n addonTerminal.write(str || data);\n }\n }\n\n addonTerminal.__sendData = (data: string) => {\n if (socket.readyState !== 1) {\n return;\n }\n socket.send(data);\n };\n\n addonTerminal._core.register(addSocketListener(socket, 'message', addonTerminal.__getMessage));\n\n if (bidirectional) {\n addonTerminal._core.register(addonTerminal.addDisposableListener('data', addonTerminal.__sendData));\n }\n\n addonTerminal._core.register(addSocketListener(socket, 'close', () => detach(addonTerminal, socket)));\n addonTerminal._core.register(addSocketListener(socket, 'error', () => detach(addonTerminal, socket)));\n}\n\nfunction addSocketListener(socket: WebSocket, type: string, handler: (this: WebSocket, ev: Event) => any): IDisposable {\n socket.addEventListener(type, handler);\n return {\n dispose: () => {\n if (!handler) {\n // Already disposed\n return;\n }\n socket.removeEventListener(type, handler);\n handler = null;\n }\n };\n}\n\n/**\n * Detaches the given terminal from the given socket\n *\n * @param term The terminal to be detached from the given socket.\n * @param socket The socket from which to detach the current terminal.\n */\nexport function detach(term: Terminal, socket: WebSocket): void {\n const addonTerminal = term;\n addonTerminal.off('data', addonTerminal.__sendData);\n\n socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket;\n\n if (socket) {\n socket.removeEventListener('message', addonTerminal.__getMessage);\n }\n\n delete addonTerminal.__socket;\n}\n\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n /**\n * Attaches the current terminal to the given socket\n *\n * @param socket The socket to attach the current terminal.\n * @param bidirectional Whether the terminal should send data to the socket as well.\n * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum\n * frequency of 1 rendering per 10ms.\n */\n (terminalConstructor.prototype).attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {\n attach(this, socket, bidirectional, buffered);\n };\n\n /**\n * Detaches the current terminal from the given socket.\n *\n * @param socket The socket from which to detach the current terminal.\n */\n (terminalConstructor.prototype).detach = function (socket: WebSocket): void {\n detach(this, socket);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADmBA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAGA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AA9EA;AAgFA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAXA;AAcA;AASA;AACA;AACA;AAOA;AACA;AACA;AACA;AArBA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/fit/fit.js b/apps/static/js/plugins/xterm/addons/fit/fit.js
new file mode 100644
index 000000000..b137d99e4
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/fit/fit.js
@@ -0,0 +1,51 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.fit = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;iterm)._core.viewport.scrollBarWidth;\n const geometry = {\n cols: Math.floor(availableWidth / (term)._core.renderer.dimensions.actualCellWidth),\n rows: Math.floor(availableHeight / (term)._core.renderer.dimensions.actualCellHeight)\n };\n return geometry;\n}\n\nexport function fit(term: Terminal): void {\n const geometry = proposeGeometry(term);\n if (geometry) {\n // Force a full render\n if (term.rows !== geometry.rows || term.cols !== geometry.cols) {\n (term)._core.renderer.clear();\n term.resize(geometry.cols, geometry.rows);\n }\n }\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n (terminalConstructor.prototype).proposeGeometry = function (): IGeometry {\n return proposeGeometry(this);\n };\n\n (terminalConstructor.prototype).fit = function (): void {\n fit(this);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADsBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAvBA;AAyBA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AARA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/fullscreen/fullscreen.css b/apps/static/js/plugins/xterm/addons/fullscreen/fullscreen.css
new file mode 100644
index 000000000..60e8c5114
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/fullscreen/fullscreen.css
@@ -0,0 +1,10 @@
+.xterm.fullscreen {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: auto;
+ height: auto;
+ z-index: 255;
+}
diff --git a/apps/static/js/plugins/xterm/addons/fullscreen/fullscreen.js b/apps/static/js/plugins/xterm/addons/fullscreen/fullscreen.js
new file mode 100644
index 000000000..d12b72e6b
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/fullscreen/fullscreen.js
@@ -0,0 +1,27 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.fullscreen = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;iterminalConstructor.prototype).toggleFullScreen = function (fullscreen: boolean): void {\n toggleFullScreen(this, fullscreen);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADYA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAZA;AAcA;AACA;AACA;AACA;AACA;AAJA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/search/search.js b/apps/static/js/plugins/xterm/addons/search/search.js
new file mode 100644
index 000000000..3a0a1d176
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/search/search.js
@@ -0,0 +1,126 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.search = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0; y--) {
+ result = this._findInLine(term, y);
+ if (result) {
+ break;
+ }
+ }
+ if (!result) {
+ for (var y = this._terminal._core.buffer.ybase + this._terminal.rows - 1; y > startRow; y--) {
+ result = this._findInLine(term, y);
+ if (result) {
+ break;
+ }
+ }
+ }
+ return this._selectResult(result);
+ };
+ SearchHelper.prototype._findInLine = function (term, y) {
+ var lowerStringLine = this._terminal._core.buffer.translateBufferLineToString(y, true).toLowerCase();
+ var lowerTerm = term.toLowerCase();
+ var searchIndex = lowerStringLine.indexOf(lowerTerm);
+ if (searchIndex >= 0) {
+ var line = this._terminal._core.buffer.lines.get(y);
+ for (var i = 0; i < searchIndex; i++) {
+ var charData = line[i];
+ var char = charData[1];
+ if (char.length > 1) {
+ searchIndex -= char.length - 1;
+ }
+ var charWidth = charData[2];
+ if (charWidth === 0) {
+ searchIndex++;
+ }
+ }
+ return {
+ term: term,
+ col: searchIndex,
+ row: y
+ };
+ }
+ };
+ SearchHelper.prototype._selectResult = function (result) {
+ if (!result) {
+ return false;
+ }
+ this._terminal._core.selectionManager.setSelection(result.col, result.row, result.term.length);
+ this._terminal.scrollLines(result.row - this._terminal._core.buffer.ydisp);
+ return true;
+ };
+ return SearchHelper;
+}());
+exports.SearchHelper = SearchHelper;
+
+},{}],2:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var SearchHelper_1 = require("./SearchHelper");
+function findNext(terminal, term) {
+ var addonTerminal = terminal;
+ if (!addonTerminal.__searchHelper) {
+ addonTerminal.__searchHelper = new SearchHelper_1.SearchHelper(addonTerminal);
+ }
+ return addonTerminal.__searchHelper.findNext(term);
+}
+exports.findNext = findNext;
+function findPrevious(terminal, term) {
+ var addonTerminal = terminal;
+ if (!addonTerminal.__searchHelper) {
+ addonTerminal.__searchHelper = new SearchHelper_1.SearchHelper(addonTerminal);
+ }
+ return addonTerminal.__searchHelper.findPrevious(term);
+}
+exports.findPrevious = findPrevious;
+function apply(terminalConstructor) {
+ terminalConstructor.prototype.findNext = function (term) {
+ return findNext(this, term);
+ };
+ terminalConstructor.prototype.findPrevious = function (term) {
+ return findPrevious(this, term);
+ };
+}
+exports.apply = apply;
+
+},{"./SearchHelper":1}]},{},[2])(2)
+});
+//# sourceMappingURL=search.js.map
diff --git a/apps/static/js/plugins/xterm/addons/search/search.js.map b/apps/static/js/plugins/xterm/addons/search/search.js.map
new file mode 100644
index 000000000..eca9836aa
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/search/search.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"search.js","sources":["../../../src/addons/search/search.ts","../../../src/addons/search/SearchHelper.ts","../../../node_modules/browser-pack/_prelude.js"],"sourcesContent":["/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { SearchHelper } from './SearchHelper';\nimport { Terminal } from 'xterm';\nimport { ISearchAddonTerminal } from './Interfaces';\n\n/**\n * Find the next instance of the term, then scroll to and select it. If it\n * doesn't exist, do nothing.\n * @param term Tne search term.\n * @return Whether a result was found.\n */\nexport function findNext(terminal: Terminal, term: string): boolean {\n const addonTerminal = terminal;\n if (!addonTerminal.__searchHelper) {\n addonTerminal.__searchHelper = new SearchHelper(addonTerminal);\n }\n return addonTerminal.__searchHelper.findNext(term);\n}\n\n/**\n * Find the previous instance of the term, then scroll to and select it. If it\n * doesn't exist, do nothing.\n * @param term Tne search term.\n * @return Whether a result was found.\n */\nexport function findPrevious(terminal: Terminal, term: string): boolean {\n const addonTerminal = terminal;\n if (!addonTerminal.__searchHelper) {\n addonTerminal.__searchHelper = new SearchHelper(addonTerminal);\n }\n return addonTerminal.__searchHelper.findPrevious(term);\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n (terminalConstructor.prototype).findNext = function(term: string): boolean {\n return findNext(this, term);\n };\n\n (terminalConstructor.prototype).findPrevious = function(term: string): boolean {\n return findPrevious(this, term);\n };\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ISearchHelper, ISearchAddonTerminal } from './Interfaces';\n\ninterface ISearchResult {\n term: string;\n col: number;\n row: number;\n}\n\n/**\n * A class that knows how to search the terminal and how to display the results.\n */\nexport class SearchHelper implements ISearchHelper {\n constructor(private _terminal: ISearchAddonTerminal) {\n // TODO: Search for multiple instances on 1 line\n // TODO: Don't use the actual selection, instead use a \"find selection\" so multiple instances can be highlighted\n // TODO: Highlight other instances in the viewport\n // TODO: Support regex, case sensitivity, etc.\n }\n\n /**\n * Find the next instance of the term, then scroll to and select it. If it\n * doesn't exist, do nothing.\n * @param term Tne search term.\n * @return Whether a result was found.\n */\n public findNext(term: string): boolean {\n if (!term || term.length === 0) {\n return false;\n }\n\n let result: ISearchResult;\n\n let startRow = this._terminal._core.buffer.ydisp;\n if (this._terminal._core.selectionManager.selectionEnd) {\n // Start from the selection end if there is a selection\n startRow = this._terminal._core.selectionManager.selectionEnd[1];\n }\n\n // Search from ydisp + 1 to end\n for (let y = startRow + 1; y < this._terminal._core.buffer.ybase + this._terminal.rows; y++) {\n result = this._findInLine(term, y);\n if (result) {\n break;\n }\n }\n\n // Search from the top to the current ydisp\n if (!result) {\n for (let y = 0; y < startRow; y++) {\n result = this._findInLine(term, y);\n if (result) {\n break;\n }\n }\n }\n\n // Set selection and scroll if a result was found\n return this._selectResult(result);\n }\n\n /**\n * Find the previous instance of the term, then scroll to and select it. If it\n * doesn't exist, do nothing.\n * @param term Tne search term.\n * @return Whether a result was found.\n */\n public findPrevious(term: string): boolean {\n if (!term || term.length === 0) {\n return false;\n }\n\n let result: ISearchResult;\n\n let startRow = this._terminal._core.buffer.ydisp;\n if (this._terminal._core.selectionManager.selectionStart) {\n // Start from the selection end if there is a selection\n startRow = this._terminal._core.selectionManager.selectionStart[1];\n }\n\n // Search from ydisp + 1 to end\n for (let y = startRow - 1; y >= 0; y--) {\n result = this._findInLine(term, y);\n if (result) {\n break;\n }\n }\n\n // Search from the top to the current ydisp\n if (!result) {\n for (let y = this._terminal._core.buffer.ybase + this._terminal.rows - 1; y > startRow; y--) {\n result = this._findInLine(term, y);\n if (result) {\n break;\n }\n }\n }\n\n // Set selection and scroll if a result was found\n return this._selectResult(result);\n }\n\n /**\n * Searches a line for a search term.\n * @param term Tne search term.\n * @param y The line to search.\n * @return The search result if it was found.\n */\n private _findInLine(term: string, y: number): ISearchResult {\n const lowerStringLine = this._terminal._core.buffer.translateBufferLineToString(y, true).toLowerCase();\n const lowerTerm = term.toLowerCase();\n let searchIndex = lowerStringLine.indexOf(lowerTerm);\n if (searchIndex >= 0) {\n const line = this._terminal._core.buffer.lines.get(y);\n for (let i = 0; i < searchIndex; i++) {\n const charData = line[i];\n // Adjust the searchIndex to normalize emoji into single chars\n const char = charData[1/*CHAR_DATA_CHAR_INDEX*/];\n if (char.length > 1) {\n searchIndex -= char.length - 1;\n }\n // Adjust the searchIndex for empty characters following wide unicode\n // chars (eg. CJK)\n const charWidth = charData[2/*CHAR_DATA_WIDTH_INDEX*/];\n if (charWidth === 0) {\n searchIndex++;\n }\n }\n return {\n term,\n col: searchIndex,\n row: y\n };\n }\n }\n\n /**\n * Selects and scrolls to a result.\n * @param result The result to select.\n * @return Whethera result was selected.\n */\n private _selectResult(result: ISearchResult): boolean {\n if (!result) {\n return false;\n }\n this._terminal._core.selectionManager.setSelection(result.col, result.row, result.term.length);\n this._terminal.scrollLines(result.row - this._terminal._core.buffer.ydisp);\n return true;\n }\n}\n",null],"names":[],"mappings":"AEAA;;;ADgBA;AACA;AAAA;AAKA;AAQA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAQA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAzIa;;;;;ADXb;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AARA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/terminado/terminado.js b/apps/static/js/plugins/xterm/addons/terminado/terminado.js
new file mode 100644
index 000000000..315629d30
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/terminado/terminado.js
@@ -0,0 +1,69 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.terminado = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;iterm;\n bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional;\n addonTerminal.__socket = socket;\n\n addonTerminal.__flushBuffer = () => {\n addonTerminal.write(addonTerminal.__attachSocketBuffer);\n addonTerminal.__attachSocketBuffer = null;\n };\n\n addonTerminal.__pushToBuffer = (data: string) => {\n if (addonTerminal.__attachSocketBuffer) {\n addonTerminal.__attachSocketBuffer += data;\n } else {\n addonTerminal.__attachSocketBuffer = data;\n setTimeout(addonTerminal.__flushBuffer, 10);\n }\n };\n\n addonTerminal.__getMessage = (ev: MessageEvent) => {\n const data = JSON.parse(ev.data);\n if (data[0] === 'stdout') {\n if (buffered) {\n addonTerminal.__pushToBuffer(data[1]);\n } else {\n addonTerminal.write(data[1]);\n }\n }\n };\n\n addonTerminal.__sendData = (data: string) => {\n socket.send(JSON.stringify(['stdin', data]));\n };\n\n addonTerminal.__setSize = (size: {rows: number, cols: number}) => {\n socket.send(JSON.stringify(['set_size', size.rows, size.cols]));\n };\n\n socket.addEventListener('message', addonTerminal.__getMessage);\n\n if (bidirectional) {\n addonTerminal.on('data', addonTerminal.__sendData);\n }\n addonTerminal.on('resize', addonTerminal.__setSize);\n\n socket.addEventListener('close', () => terminadoDetach(addonTerminal, socket));\n socket.addEventListener('error', () => terminadoDetach(addonTerminal, socket));\n}\n\n/**\n * Detaches the given terminal from the given socket\n *\n * @param term The terminal to be detached from the given socket.\n * @param socket The socket from which to detach the current terminal.\n */\nexport function terminadoDetach(term: Terminal, socket: WebSocket): void {\n const addonTerminal = term;\n addonTerminal.off('data', addonTerminal.__sendData);\n\n socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket;\n\n if (socket) {\n socket.removeEventListener('message', addonTerminal.__getMessage);\n }\n\n delete addonTerminal.__socket;\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n /**\n * Attaches the current terminal to the given socket\n *\n * @param socket - The socket to attach the current terminal.\n * @param bidirectional - Whether the terminal should send data to the socket as well.\n * @param buffered - Whether the rendering of incoming data should happen instantly or at a\n * maximum frequency of 1 rendering per 10ms.\n */\n (terminalConstructor.prototype).terminadoAttach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {\n return terminadoAttach(this, socket, bidirectional, buffered);\n };\n\n /**\n * Detaches the current terminal from the given socket.\n *\n * @param socket The socket from which to detach the current terminal.\n */\n (terminalConstructor.prototype).terminadoDetach = function (socket: WebSocket): void {\n return terminadoDetach(this, socket);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADoBA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AA/CA;AAuDA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAXA;AAaA;AASA;AACA;AACA;AAOA;AACA;AACA;AACA;AArBA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/webLinks/webLinks.js b/apps/static/js/plugins/xterm/addons/webLinks/webLinks.js
new file mode 100644
index 000000000..42208846b
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/webLinks/webLinks.js
@@ -0,0 +1,41 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.webLinks = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i void = handleLink, options: ILinkMatcherOptions = {}): void {\n options.matchIndex = 1;\n term.registerLinkMatcher(strictUrlRegex, handler, options);\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n (terminalConstructor.prototype).webLinksInit = function (handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void {\n webLinksInit(this, handler, options);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAQA;AAAA;AAAA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AACA;AAJA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/winptyCompat/winptyCompat.js b/apps/static/js/plugins/xterm/addons/winptyCompat/winptyCompat.js
new file mode 100644
index 000000000..641c56ff7
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/winptyCompat/winptyCompat.js
@@ -0,0 +1,29 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.winptyCompat = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0;
+ if (!isWindows) {
+ return;
+ }
+ addonTerminal.on('linefeed', function () {
+ var line = addonTerminal._core.buffer.lines.get(addonTerminal._core.buffer.ybase + addonTerminal._core.buffer.y - 1);
+ var lastChar = line[addonTerminal.cols - 1];
+ if (lastChar[3] !== 32) {
+ var nextLine = addonTerminal._core.buffer.lines.get(addonTerminal._core.buffer.ybase + addonTerminal._core.buffer.y);
+ nextLine.isWrapped = true;
+ }
+ });
+}
+exports.winptyCompatInit = winptyCompatInit;
+function apply(terminalConstructor) {
+ terminalConstructor.prototype.winptyCompatInit = function () {
+ winptyCompatInit(this);
+ };
+}
+exports.apply = apply;
+
+},{}]},{},[1])(1)
+});
+//# sourceMappingURL=winptyCompat.js.map
diff --git a/apps/static/js/plugins/xterm/addons/winptyCompat/winptyCompat.js.map b/apps/static/js/plugins/xterm/addons/winptyCompat/winptyCompat.js.map
new file mode 100644
index 000000000..da8f4acb1
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/winptyCompat/winptyCompat.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"winptyCompat.js","sources":["../../../src/addons/winptyCompat/winptyCompat.ts","../../../node_modules/browser-pack/_prelude.js"],"sourcesContent":["/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { Terminal } from 'xterm';\nimport { IWinptyCompatAddonTerminal } from './Interfaces';\n\nexport function winptyCompatInit(terminal: Terminal): void {\n const addonTerminal = terminal;\n\n // Don't do anything when the platform is not Windows\n const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;\n if (!isWindows) {\n return;\n }\n\n // Winpty does not support wraparound mode which means that lines will never\n // be marked as wrapped. This causes issues for things like copying a line\n // retaining the wrapped new line characters or if consumers are listening\n // in on the data stream.\n //\n // The workaround for this is to listen to every incoming line feed and mark\n // the line as wrapped if the last character in the previous line is not a\n // space. This is certainly not without its problems, but generally on\n // Windows when text reaches the end of the terminal it's likely going to be\n // wrapped.\n addonTerminal.on('linefeed', () => {\n const line = addonTerminal._core.buffer.lines.get(addonTerminal._core.buffer.ybase + addonTerminal._core.buffer.y - 1);\n const lastChar = line[addonTerminal.cols - 1];\n\n if (lastChar[3] !== 32 /* ' ' */) {\n const nextLine = addonTerminal._core.buffer.lines.get(addonTerminal._core.buffer.ybase + addonTerminal._core.buffer.y);\n (nextLine).isWrapped = true;\n }\n });\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n (terminalConstructor.prototype).winptyCompatInit = function (): void {\n winptyCompatInit(this);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADQA;AACA;AAGA;AACA;AACA;AACA;AAYA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AA5BA;AA8BA;AACA;AACA;AACA;AACA;AAJA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/addons/zmodem/zmodem.js b/apps/static/js/plugins/xterm/addons/zmodem/zmodem.js
new file mode 100644
index 000000000..70a7ff773
--- /dev/null
+++ b/apps/static/js/plugins/xterm/addons/zmodem/zmodem.js
@@ -0,0 +1,45 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.zmodem = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i, )` - creates a Zmodem.Sentry\n * on the passed WebSocket object. The Object passed is optional and\n * can contain:\n * - noTerminalWriteOutsideSession: Suppress writes from the Sentry\n * object to the Terminal while there is no active Session. This\n * is necessary for compatibility with, for example, the\n * `attach.js` addon.\n *\n * - event `zmodemDetect` - fired on Zmodem.Sentry’s `on_detect` callback.\n * Passes the zmodem.js Detection object.\n *\n * - event `zmodemRetract` - fired on Zmodem.Sentry’s `on_retract` callback.\n *\n * You’ll need to provide logic to handle uploads and downloads.\n * See zmodem.js’s documentation for more details.\n *\n * **IMPORTANT:** After you confirm() a zmodem.js Detection, if you have\n * used the `attach` or `terminado` addons, you’ll need to suspend their\n * operation for the duration of the ZMODEM session. (The demo does this\n * via `detach()` and a re-`attach()`.)\n */\n\nlet zmodem;\n\nexport interface IZmodemOptions {\n noTerminalWriteOutsideSession?: boolean;\n}\n\nfunction zmodemAttach(ws: WebSocket, opts: IZmodemOptions = {}): void {\n const term = this;\n const senderFunc = (octets: ArrayLike) => ws.send(new Uint8Array(octets));\n\n let zsentry;\n\n function shouldWrite(): boolean {\n return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession;\n }\n\n zsentry = new zmodem.Sentry({\n to_terminal: (octets: ArrayLike) => {\n if (shouldWrite()) {\n term.write(\n String.fromCharCode.apply(String, octets)\n );\n }\n },\n sender: senderFunc,\n on_retract: () => (term).emit('zmodemRetract'),\n on_detect: (detection: any) => (term).emit('zmodemDetect', detection)\n });\n\n function handleWSMessage(evt: MessageEvent): void {\n\n // In testing with xterm.js’s demo the first message was\n // always text even if the rest were binary. While that\n // may be specific to xterm.js’s demo, ultimately we\n // should reject anything that isn’t binary.\n if (typeof evt.data === 'string') {\n if (shouldWrite()) {\n term.write(evt.data);\n }\n }\n else {\n zsentry.consume(evt.data);\n }\n }\n\n ws.binaryType = 'arraybuffer';\n ws.addEventListener('message', handleWSMessage);\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n zmodem = (typeof window === 'object') ? (window).Zmodem : {Browser: null}; // Nullify browser for tests\n\n (terminalConstructor.prototype).zmodemAttach = zmodemAttach;\n (terminalConstructor.prototype).zmodemBrowser = zmodem.Browser;\n}\n",null],"names":[],"mappings":"ACAA;;;ADoCA;AAMA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AALA;"}
\ No newline at end of file
diff --git a/apps/static/js/plugins/xterm/xterm.css b/apps/static/js/plugins/xterm/xterm.css
index 89daf9e3e..8e129f50f 100644
--- a/apps/static/js/plugins/xterm/xterm.css
+++ b/apps/static/js/plugins/xterm/xterm.css
@@ -1,8 +1,8 @@
/**
- * xterm.js: xterm, in the browser
- * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License)
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
+ * @license MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,13 +31,11 @@
* other features.
*/
-/*
- * Default style for xterm.js
+/**
+ * Default styles for xterm.js
*/
-.terminal {
- background-color: #000;
- color: #fff;
+.xterm {
font-family: courier-new, courier, monospace;
font-feature-settings: "liga" 0;
position: relative;
@@ -46,17 +44,22 @@
-webkit-user-select: none;
}
-.terminal.focus,
-.terminal:focus {
+.xterm.focus,
+.xterm:focus {
outline: none;
}
-.terminal .xterm-helpers {
+.xterm .xterm-helpers {
position: absolute;
top: 0;
+ /**
+ * The z-index of the helpers must be higher than the canvases in order for
+ * IMEs to appear on top.
+ */
+ z-index: 10;
}
-.terminal .xterm-helper-textarea {
+.xterm .xterm-helper-textarea {
/*
* HACK: to fix IE's blinking cursor
* Move textarea out of the screen to the far left, so that the cursor is not visible.
@@ -74,57 +77,8 @@
resize: none;
}
-.terminal a {
- color: inherit;
- text-decoration: none;
-}
-
-.terminal a:hover {
- cursor: pointer;
- text-decoration: underline;
-}
-
-.terminal a.xterm-invalid-link:hover {
- cursor: text;
- text-decoration: none;
-}
-
-.terminal .terminal-cursor {
- position: relative;
-}
-
-.terminal:not(.focus) .terminal-cursor {
- outline: 1px solid #fff;
- outline-offset: -1px;
-}
-
-.terminal.xterm-cursor-style-block.focus:not(.xterm-cursor-blink-on) .terminal-cursor {
- background-color: #fff;
- color: #000;
-}
-
-.terminal.focus.xterm-cursor-style-bar:not(.xterm-cursor-blink-on) .terminal-cursor::before,
-.terminal.focus.xterm-cursor-style-underline:not(.xterm-cursor-blink-on) .terminal-cursor::before {
- content: '';
- position: absolute;
- background-color: #fff;
-}
-
-.terminal.focus.xterm-cursor-style-bar:not(.xterm-cursor-blink-on) .terminal-cursor::before {
- top: 0;
- left: 0;
- bottom: 0;
- width: 1px;
-}
-
-.terminal.focus.xterm-cursor-style-underline:not(.xterm-cursor-blink-on) .terminal-cursor::before {
- bottom: 0;
- left: 0;
- right: 0;
- height: 1px;
-}
-
-.terminal .composition-view {
+.xterm .composition-view {
+ /* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
display: none;
@@ -133,2129 +87,78 @@
z-index: 1;
}
-.terminal .composition-view.active {
+.xterm .composition-view.active {
display: block;
}
-.terminal .xterm-viewport {
+.xterm .xterm-viewport {
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
+ cursor: default;
+ position: absolute;
+ right: 0;
+ left: 0;
+ top: 0;
+ bottom: 0;
}
-.terminal .xterm-wide-char,
-.terminal .xterm-normal-char {
- display: inline-block;
+.xterm .xterm-screen {
+ position: relative;
}
-.terminal .xterm-rows {
+.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
-.terminal .xterm-rows > div {
- /* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */
- white-space: nowrap;
-}
-
-.terminal .xterm-scroll-area {
+.xterm .xterm-scroll-area {
visibility: hidden;
}
-.terminal .xterm-char-measure-element {
+.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
+ top: 0;
left: -9999em;
+ line-height: normal;
}
-.terminal.enable-mouse-events {
+.xterm {
+ cursor: text;
+}
+
+.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
-.terminal .xterm-selection {
+.xterm.xterm-cursor-pointer {
+ cursor: pointer;
+}
+
+.xterm.xterm-cursor-crosshair {
+ /* Column selection mode */
+ cursor: crosshair;
+}
+
+.xterm .xterm-accessibility,
+.xterm .xterm-message {
position: absolute;
- top: 0;
left: 0;
- z-index: 1;
- opacity: 0.3;
- pointer-events: none;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ z-index: 100;
+ color: transparent;
}
-.terminal .xterm-selection div {
+.xterm .live-region {
position: absolute;
- background-color: #fff;
-}
-
-/*
- * Determine default colors for xterm.js
- */
-.terminal .xterm-bold {
- font-weight: bold;
-}
-
-.terminal .xterm-underline {
- text-decoration: underline;
-}
-
-.terminal .xterm-blink {
- text-decoration: blink;
-}
-
-.terminal .xterm-blink.xterm-underline {
- text-decoration: blink underline;
-}
-
-.terminal .xterm-hidden {
- visibility: hidden;
-}
-
-.terminal .xterm-color-0 {
- color: #2e3436;
-}
-
-.terminal .xterm-bg-color-0 {
- background-color: #2e3436;
-}
-
-.terminal .xterm-color-1 {
- color: #cc0000;
-}
-
-.terminal .xterm-bg-color-1 {
- background-color: #cc0000;
-}
-
-.terminal .xterm-color-2 {
- color: #4e9a06;
-}
-
-.terminal .xterm-bg-color-2 {
- background-color: #4e9a06;
-}
-
-.terminal .xterm-color-3 {
- color: #c4a000;
-}
-
-.terminal .xterm-bg-color-3 {
- background-color: #c4a000;
-}
-
-.terminal .xterm-color-4 {
- color: #3465a4;
-}
-
-.terminal .xterm-bg-color-4 {
- background-color: #3465a4;
-}
-
-.terminal .xterm-color-5 {
- color: #75507b;
-}
-
-.terminal .xterm-bg-color-5 {
- background-color: #75507b;
-}
-
-.terminal .xterm-color-6 {
- color: #06989a;
-}
-
-.terminal .xterm-bg-color-6 {
- background-color: #06989a;
-}
-
-.terminal .xterm-color-7 {
- color: #d3d7cf;
-}
-
-.terminal .xterm-bg-color-7 {
- background-color: #d3d7cf;
-}
-
-.terminal .xterm-color-8 {
- color: #555753;
-}
-
-.terminal .xterm-bg-color-8 {
- background-color: #555753;
-}
-
-.terminal .xterm-color-9 {
- color: #ef2929;
-}
-
-.terminal .xterm-bg-color-9 {
- background-color: #ef2929;
-}
-
-.terminal .xterm-color-10 {
- color: #8ae234;
-}
-
-.terminal .xterm-bg-color-10 {
- background-color: #8ae234;
-}
-
-.terminal .xterm-color-11 {
- color: #fce94f;
-}
-
-.terminal .xterm-bg-color-11 {
- background-color: #fce94f;
-}
-
-.terminal .xterm-color-12 {
- color: #729fcf;
-}
-
-.terminal .xterm-bg-color-12 {
- background-color: #729fcf;
-}
-
-.terminal .xterm-color-13 {
- color: #ad7fa8;
-}
-
-.terminal .xterm-bg-color-13 {
- background-color: #ad7fa8;
-}
-
-.terminal .xterm-color-14 {
- color: #34e2e2;
-}
-
-.terminal .xterm-bg-color-14 {
- background-color: #34e2e2;
-}
-
-.terminal .xterm-color-15 {
- color: #eeeeec;
-}
-
-.terminal .xterm-bg-color-15 {
- background-color: #eeeeec;
-}
-
-.terminal .xterm-color-16 {
- color: #000000;
-}
-
-.terminal .xterm-bg-color-16 {
- background-color: #000000;
-}
-
-.terminal .xterm-color-17 {
- color: #00005f;
-}
-
-.terminal .xterm-bg-color-17 {
- background-color: #00005f;
-}
-
-.terminal .xterm-color-18 {
- color: #000087;
-}
-
-.terminal .xterm-bg-color-18 {
- background-color: #000087;
-}
-
-.terminal .xterm-color-19 {
- color: #0000af;
-}
-
-.terminal .xterm-bg-color-19 {
- background-color: #0000af;
-}
-
-.terminal .xterm-color-20 {
- color: #0000d7;
-}
-
-.terminal .xterm-bg-color-20 {
- background-color: #0000d7;
-}
-
-.terminal .xterm-color-21 {
- color: #0000ff;
-}
-
-.terminal .xterm-bg-color-21 {
- background-color: #0000ff;
-}
-
-.terminal .xterm-color-22 {
- color: #005f00;
-}
-
-.terminal .xterm-bg-color-22 {
- background-color: #005f00;
-}
-
-.terminal .xterm-color-23 {
- color: #005f5f;
-}
-
-.terminal .xterm-bg-color-23 {
- background-color: #005f5f;
-}
-
-.terminal .xterm-color-24 {
- color: #005f87;
-}
-
-.terminal .xterm-bg-color-24 {
- background-color: #005f87;
-}
-
-.terminal .xterm-color-25 {
- color: #005faf;
-}
-
-.terminal .xterm-bg-color-25 {
- background-color: #005faf;
-}
-
-.terminal .xterm-color-26 {
- color: #005fd7;
-}
-
-.terminal .xterm-bg-color-26 {
- background-color: #005fd7;
-}
-
-.terminal .xterm-color-27 {
- color: #005fff;
-}
-
-.terminal .xterm-bg-color-27 {
- background-color: #005fff;
-}
-
-.terminal .xterm-color-28 {
- color: #008700;
-}
-
-.terminal .xterm-bg-color-28 {
- background-color: #008700;
-}
-
-.terminal .xterm-color-29 {
- color: #00875f;
-}
-
-.terminal .xterm-bg-color-29 {
- background-color: #00875f;
-}
-
-.terminal .xterm-color-30 {
- color: #008787;
-}
-
-.terminal .xterm-bg-color-30 {
- background-color: #008787;
-}
-
-.terminal .xterm-color-31 {
- color: #0087af;
-}
-
-.terminal .xterm-bg-color-31 {
- background-color: #0087af;
-}
-
-.terminal .xterm-color-32 {
- color: #0087d7;
-}
-
-.terminal .xterm-bg-color-32 {
- background-color: #0087d7;
-}
-
-.terminal .xterm-color-33 {
- color: #0087ff;
-}
-
-.terminal .xterm-bg-color-33 {
- background-color: #0087ff;
-}
-
-.terminal .xterm-color-34 {
- color: #00af00;
-}
-
-.terminal .xterm-bg-color-34 {
- background-color: #00af00;
-}
-
-.terminal .xterm-color-35 {
- color: #00af5f;
-}
-
-.terminal .xterm-bg-color-35 {
- background-color: #00af5f;
-}
-
-.terminal .xterm-color-36 {
- color: #00af87;
-}
-
-.terminal .xterm-bg-color-36 {
- background-color: #00af87;
-}
-
-.terminal .xterm-color-37 {
- color: #00afaf;
-}
-
-.terminal .xterm-bg-color-37 {
- background-color: #00afaf;
-}
-
-.terminal .xterm-color-38 {
- color: #00afd7;
-}
-
-.terminal .xterm-bg-color-38 {
- background-color: #00afd7;
-}
-
-.terminal .xterm-color-39 {
- color: #00afff;
-}
-
-.terminal .xterm-bg-color-39 {
- background-color: #00afff;
-}
-
-.terminal .xterm-color-40 {
- color: #00d700;
-}
-
-.terminal .xterm-bg-color-40 {
- background-color: #00d700;
-}
-
-.terminal .xterm-color-41 {
- color: #00d75f;
-}
-
-.terminal .xterm-bg-color-41 {
- background-color: #00d75f;
-}
-
-.terminal .xterm-color-42 {
- color: #00d787;
-}
-
-.terminal .xterm-bg-color-42 {
- background-color: #00d787;
-}
-
-.terminal .xterm-color-43 {
- color: #00d7af;
-}
-
-.terminal .xterm-bg-color-43 {
- background-color: #00d7af;
-}
-
-.terminal .xterm-color-44 {
- color: #00d7d7;
-}
-
-.terminal .xterm-bg-color-44 {
- background-color: #00d7d7;
-}
-
-.terminal .xterm-color-45 {
- color: #00d7ff;
-}
-
-.terminal .xterm-bg-color-45 {
- background-color: #00d7ff;
-}
-
-.terminal .xterm-color-46 {
- color: #00ff00;
-}
-
-.terminal .xterm-bg-color-46 {
- background-color: #00ff00;
-}
-
-.terminal .xterm-color-47 {
- color: #00ff5f;
-}
-
-.terminal .xterm-bg-color-47 {
- background-color: #00ff5f;
-}
-
-.terminal .xterm-color-48 {
- color: #00ff87;
-}
-
-.terminal .xterm-bg-color-48 {
- background-color: #00ff87;
-}
-
-.terminal .xterm-color-49 {
- color: #00ffaf;
-}
-
-.terminal .xterm-bg-color-49 {
- background-color: #00ffaf;
-}
-
-.terminal .xterm-color-50 {
- color: #00ffd7;
-}
-
-.terminal .xterm-bg-color-50 {
- background-color: #00ffd7;
-}
-
-.terminal .xterm-color-51 {
- color: #00ffff;
-}
-
-.terminal .xterm-bg-color-51 {
- background-color: #00ffff;
-}
-
-.terminal .xterm-color-52 {
- color: #5f0000;
-}
-
-.terminal .xterm-bg-color-52 {
- background-color: #5f0000;
-}
-
-.terminal .xterm-color-53 {
- color: #5f005f;
-}
-
-.terminal .xterm-bg-color-53 {
- background-color: #5f005f;
-}
-
-.terminal .xterm-color-54 {
- color: #5f0087;
-}
-
-.terminal .xterm-bg-color-54 {
- background-color: #5f0087;
-}
-
-.terminal .xterm-color-55 {
- color: #5f00af;
-}
-
-.terminal .xterm-bg-color-55 {
- background-color: #5f00af;
-}
-
-.terminal .xterm-color-56 {
- color: #5f00d7;
-}
-
-.terminal .xterm-bg-color-56 {
- background-color: #5f00d7;
-}
-
-.terminal .xterm-color-57 {
- color: #5f00ff;
-}
-
-.terminal .xterm-bg-color-57 {
- background-color: #5f00ff;
-}
-
-.terminal .xterm-color-58 {
- color: #5f5f00;
-}
-
-.terminal .xterm-bg-color-58 {
- background-color: #5f5f00;
-}
-
-.terminal .xterm-color-59 {
- color: #5f5f5f;
-}
-
-.terminal .xterm-bg-color-59 {
- background-color: #5f5f5f;
-}
-
-.terminal .xterm-color-60 {
- color: #5f5f87;
-}
-
-.terminal .xterm-bg-color-60 {
- background-color: #5f5f87;
-}
-
-.terminal .xterm-color-61 {
- color: #5f5faf;
-}
-
-.terminal .xterm-bg-color-61 {
- background-color: #5f5faf;
-}
-
-.terminal .xterm-color-62 {
- color: #5f5fd7;
-}
-
-.terminal .xterm-bg-color-62 {
- background-color: #5f5fd7;
-}
-
-.terminal .xterm-color-63 {
- color: #5f5fff;
-}
-
-.terminal .xterm-bg-color-63 {
- background-color: #5f5fff;
-}
-
-.terminal .xterm-color-64 {
- color: #5f8700;
-}
-
-.terminal .xterm-bg-color-64 {
- background-color: #5f8700;
-}
-
-.terminal .xterm-color-65 {
- color: #5f875f;
-}
-
-.terminal .xterm-bg-color-65 {
- background-color: #5f875f;
-}
-
-.terminal .xterm-color-66 {
- color: #5f8787;
-}
-
-.terminal .xterm-bg-color-66 {
- background-color: #5f8787;
-}
-
-.terminal .xterm-color-67 {
- color: #5f87af;
-}
-
-.terminal .xterm-bg-color-67 {
- background-color: #5f87af;
-}
-
-.terminal .xterm-color-68 {
- color: #5f87d7;
-}
-
-.terminal .xterm-bg-color-68 {
- background-color: #5f87d7;
-}
-
-.terminal .xterm-color-69 {
- color: #5f87ff;
-}
-
-.terminal .xterm-bg-color-69 {
- background-color: #5f87ff;
-}
-
-.terminal .xterm-color-70 {
- color: #5faf00;
-}
-
-.terminal .xterm-bg-color-70 {
- background-color: #5faf00;
-}
-
-.terminal .xterm-color-71 {
- color: #5faf5f;
-}
-
-.terminal .xterm-bg-color-71 {
- background-color: #5faf5f;
-}
-
-.terminal .xterm-color-72 {
- color: #5faf87;
-}
-
-.terminal .xterm-bg-color-72 {
- background-color: #5faf87;
-}
-
-.terminal .xterm-color-73 {
- color: #5fafaf;
-}
-
-.terminal .xterm-bg-color-73 {
- background-color: #5fafaf;
-}
-
-.terminal .xterm-color-74 {
- color: #5fafd7;
-}
-
-.terminal .xterm-bg-color-74 {
- background-color: #5fafd7;
-}
-
-.terminal .xterm-color-75 {
- color: #5fafff;
-}
-
-.terminal .xterm-bg-color-75 {
- background-color: #5fafff;
-}
-
-.terminal .xterm-color-76 {
- color: #5fd700;
-}
-
-.terminal .xterm-bg-color-76 {
- background-color: #5fd700;
-}
-
-.terminal .xterm-color-77 {
- color: #5fd75f;
-}
-
-.terminal .xterm-bg-color-77 {
- background-color: #5fd75f;
-}
-
-.terminal .xterm-color-78 {
- color: #5fd787;
-}
-
-.terminal .xterm-bg-color-78 {
- background-color: #5fd787;
-}
-
-.terminal .xterm-color-79 {
- color: #5fd7af;
-}
-
-.terminal .xterm-bg-color-79 {
- background-color: #5fd7af;
-}
-
-.terminal .xterm-color-80 {
- color: #5fd7d7;
-}
-
-.terminal .xterm-bg-color-80 {
- background-color: #5fd7d7;
-}
-
-.terminal .xterm-color-81 {
- color: #5fd7ff;
-}
-
-.terminal .xterm-bg-color-81 {
- background-color: #5fd7ff;
-}
-
-.terminal .xterm-color-82 {
- color: #5fff00;
-}
-
-.terminal .xterm-bg-color-82 {
- background-color: #5fff00;
-}
-
-.terminal .xterm-color-83 {
- color: #5fff5f;
-}
-
-.terminal .xterm-bg-color-83 {
- background-color: #5fff5f;
-}
-
-.terminal .xterm-color-84 {
- color: #5fff87;
-}
-
-.terminal .xterm-bg-color-84 {
- background-color: #5fff87;
-}
-
-.terminal .xterm-color-85 {
- color: #5fffaf;
-}
-
-.terminal .xterm-bg-color-85 {
- background-color: #5fffaf;
-}
-
-.terminal .xterm-color-86 {
- color: #5fffd7;
-}
-
-.terminal .xterm-bg-color-86 {
- background-color: #5fffd7;
-}
-
-.terminal .xterm-color-87 {
- color: #5fffff;
-}
-
-.terminal .xterm-bg-color-87 {
- background-color: #5fffff;
-}
-
-.terminal .xterm-color-88 {
- color: #870000;
-}
-
-.terminal .xterm-bg-color-88 {
- background-color: #870000;
-}
-
-.terminal .xterm-color-89 {
- color: #87005f;
-}
-
-.terminal .xterm-bg-color-89 {
- background-color: #87005f;
-}
-
-.terminal .xterm-color-90 {
- color: #870087;
-}
-
-.terminal .xterm-bg-color-90 {
- background-color: #870087;
-}
-
-.terminal .xterm-color-91 {
- color: #8700af;
-}
-
-.terminal .xterm-bg-color-91 {
- background-color: #8700af;
-}
-
-.terminal .xterm-color-92 {
- color: #8700d7;
-}
-
-.terminal .xterm-bg-color-92 {
- background-color: #8700d7;
-}
-
-.terminal .xterm-color-93 {
- color: #8700ff;
-}
-
-.terminal .xterm-bg-color-93 {
- background-color: #8700ff;
-}
-
-.terminal .xterm-color-94 {
- color: #875f00;
-}
-
-.terminal .xterm-bg-color-94 {
- background-color: #875f00;
-}
-
-.terminal .xterm-color-95 {
- color: #875f5f;
-}
-
-.terminal .xterm-bg-color-95 {
- background-color: #875f5f;
-}
-
-.terminal .xterm-color-96 {
- color: #875f87;
-}
-
-.terminal .xterm-bg-color-96 {
- background-color: #875f87;
-}
-
-.terminal .xterm-color-97 {
- color: #875faf;
-}
-
-.terminal .xterm-bg-color-97 {
- background-color: #875faf;
-}
-
-.terminal .xterm-color-98 {
- color: #875fd7;
-}
-
-.terminal .xterm-bg-color-98 {
- background-color: #875fd7;
-}
-
-.terminal .xterm-color-99 {
- color: #875fff;
-}
-
-.terminal .xterm-bg-color-99 {
- background-color: #875fff;
-}
-
-.terminal .xterm-color-100 {
- color: #878700;
-}
-
-.terminal .xterm-bg-color-100 {
- background-color: #878700;
-}
-
-.terminal .xterm-color-101 {
- color: #87875f;
-}
-
-.terminal .xterm-bg-color-101 {
- background-color: #87875f;
-}
-
-.terminal .xterm-color-102 {
- color: #878787;
-}
-
-.terminal .xterm-bg-color-102 {
- background-color: #878787;
-}
-
-.terminal .xterm-color-103 {
- color: #8787af;
-}
-
-.terminal .xterm-bg-color-103 {
- background-color: #8787af;
-}
-
-.terminal .xterm-color-104 {
- color: #8787d7;
-}
-
-.terminal .xterm-bg-color-104 {
- background-color: #8787d7;
-}
-
-.terminal .xterm-color-105 {
- color: #8787ff;
-}
-
-.terminal .xterm-bg-color-105 {
- background-color: #8787ff;
-}
-
-.terminal .xterm-color-106 {
- color: #87af00;
-}
-
-.terminal .xterm-bg-color-106 {
- background-color: #87af00;
-}
-
-.terminal .xterm-color-107 {
- color: #87af5f;
-}
-
-.terminal .xterm-bg-color-107 {
- background-color: #87af5f;
-}
-
-.terminal .xterm-color-108 {
- color: #87af87;
-}
-
-.terminal .xterm-bg-color-108 {
- background-color: #87af87;
-}
-
-.terminal .xterm-color-109 {
- color: #87afaf;
-}
-
-.terminal .xterm-bg-color-109 {
- background-color: #87afaf;
-}
-
-.terminal .xterm-color-110 {
- color: #87afd7;
-}
-
-.terminal .xterm-bg-color-110 {
- background-color: #87afd7;
-}
-
-.terminal .xterm-color-111 {
- color: #87afff;
-}
-
-.terminal .xterm-bg-color-111 {
- background-color: #87afff;
-}
-
-.terminal .xterm-color-112 {
- color: #87d700;
-}
-
-.terminal .xterm-bg-color-112 {
- background-color: #87d700;
-}
-
-.terminal .xterm-color-113 {
- color: #87d75f;
-}
-
-.terminal .xterm-bg-color-113 {
- background-color: #87d75f;
-}
-
-.terminal .xterm-color-114 {
- color: #87d787;
-}
-
-.terminal .xterm-bg-color-114 {
- background-color: #87d787;
-}
-
-.terminal .xterm-color-115 {
- color: #87d7af;
-}
-
-.terminal .xterm-bg-color-115 {
- background-color: #87d7af;
-}
-
-.terminal .xterm-color-116 {
- color: #87d7d7;
-}
-
-.terminal .xterm-bg-color-116 {
- background-color: #87d7d7;
-}
-
-.terminal .xterm-color-117 {
- color: #87d7ff;
-}
-
-.terminal .xterm-bg-color-117 {
- background-color: #87d7ff;
-}
-
-.terminal .xterm-color-118 {
- color: #87ff00;
-}
-
-.terminal .xterm-bg-color-118 {
- background-color: #87ff00;
-}
-
-.terminal .xterm-color-119 {
- color: #87ff5f;
-}
-
-.terminal .xterm-bg-color-119 {
- background-color: #87ff5f;
-}
-
-.terminal .xterm-color-120 {
- color: #87ff87;
-}
-
-.terminal .xterm-bg-color-120 {
- background-color: #87ff87;
-}
-
-.terminal .xterm-color-121 {
- color: #87ffaf;
-}
-
-.terminal .xterm-bg-color-121 {
- background-color: #87ffaf;
-}
-
-.terminal .xterm-color-122 {
- color: #87ffd7;
-}
-
-.terminal .xterm-bg-color-122 {
- background-color: #87ffd7;
-}
-
-.terminal .xterm-color-123 {
- color: #87ffff;
-}
-
-.terminal .xterm-bg-color-123 {
- background-color: #87ffff;
-}
-
-.terminal .xterm-color-124 {
- color: #af0000;
-}
-
-.terminal .xterm-bg-color-124 {
- background-color: #af0000;
-}
-
-.terminal .xterm-color-125 {
- color: #af005f;
-}
-
-.terminal .xterm-bg-color-125 {
- background-color: #af005f;
-}
-
-.terminal .xterm-color-126 {
- color: #af0087;
-}
-
-.terminal .xterm-bg-color-126 {
- background-color: #af0087;
-}
-
-.terminal .xterm-color-127 {
- color: #af00af;
-}
-
-.terminal .xterm-bg-color-127 {
- background-color: #af00af;
-}
-
-.terminal .xterm-color-128 {
- color: #af00d7;
-}
-
-.terminal .xterm-bg-color-128 {
- background-color: #af00d7;
-}
-
-.terminal .xterm-color-129 {
- color: #af00ff;
-}
-
-.terminal .xterm-bg-color-129 {
- background-color: #af00ff;
-}
-
-.terminal .xterm-color-130 {
- color: #af5f00;
-}
-
-.terminal .xterm-bg-color-130 {
- background-color: #af5f00;
-}
-
-.terminal .xterm-color-131 {
- color: #af5f5f;
-}
-
-.terminal .xterm-bg-color-131 {
- background-color: #af5f5f;
-}
-
-.terminal .xterm-color-132 {
- color: #af5f87;
-}
-
-.terminal .xterm-bg-color-132 {
- background-color: #af5f87;
-}
-
-.terminal .xterm-color-133 {
- color: #af5faf;
-}
-
-.terminal .xterm-bg-color-133 {
- background-color: #af5faf;
-}
-
-.terminal .xterm-color-134 {
- color: #af5fd7;
-}
-
-.terminal .xterm-bg-color-134 {
- background-color: #af5fd7;
-}
-
-.terminal .xterm-color-135 {
- color: #af5fff;
-}
-
-.terminal .xterm-bg-color-135 {
- background-color: #af5fff;
-}
-
-.terminal .xterm-color-136 {
- color: #af8700;
-}
-
-.terminal .xterm-bg-color-136 {
- background-color: #af8700;
-}
-
-.terminal .xterm-color-137 {
- color: #af875f;
-}
-
-.terminal .xterm-bg-color-137 {
- background-color: #af875f;
-}
-
-.terminal .xterm-color-138 {
- color: #af8787;
-}
-
-.terminal .xterm-bg-color-138 {
- background-color: #af8787;
-}
-
-.terminal .xterm-color-139 {
- color: #af87af;
-}
-
-.terminal .xterm-bg-color-139 {
- background-color: #af87af;
-}
-
-.terminal .xterm-color-140 {
- color: #af87d7;
-}
-
-.terminal .xterm-bg-color-140 {
- background-color: #af87d7;
-}
-
-.terminal .xterm-color-141 {
- color: #af87ff;
-}
-
-.terminal .xterm-bg-color-141 {
- background-color: #af87ff;
-}
-
-.terminal .xterm-color-142 {
- color: #afaf00;
-}
-
-.terminal .xterm-bg-color-142 {
- background-color: #afaf00;
-}
-
-.terminal .xterm-color-143 {
- color: #afaf5f;
-}
-
-.terminal .xterm-bg-color-143 {
- background-color: #afaf5f;
-}
-
-.terminal .xterm-color-144 {
- color: #afaf87;
-}
-
-.terminal .xterm-bg-color-144 {
- background-color: #afaf87;
-}
-
-.terminal .xterm-color-145 {
- color: #afafaf;
-}
-
-.terminal .xterm-bg-color-145 {
- background-color: #afafaf;
-}
-
-.terminal .xterm-color-146 {
- color: #afafd7;
-}
-
-.terminal .xterm-bg-color-146 {
- background-color: #afafd7;
-}
-
-.terminal .xterm-color-147 {
- color: #afafff;
-}
-
-.terminal .xterm-bg-color-147 {
- background-color: #afafff;
-}
-
-.terminal .xterm-color-148 {
- color: #afd700;
-}
-
-.terminal .xterm-bg-color-148 {
- background-color: #afd700;
-}
-
-.terminal .xterm-color-149 {
- color: #afd75f;
-}
-
-.terminal .xterm-bg-color-149 {
- background-color: #afd75f;
-}
-
-.terminal .xterm-color-150 {
- color: #afd787;
-}
-
-.terminal .xterm-bg-color-150 {
- background-color: #afd787;
-}
-
-.terminal .xterm-color-151 {
- color: #afd7af;
-}
-
-.terminal .xterm-bg-color-151 {
- background-color: #afd7af;
-}
-
-.terminal .xterm-color-152 {
- color: #afd7d7;
-}
-
-.terminal .xterm-bg-color-152 {
- background-color: #afd7d7;
-}
-
-.terminal .xterm-color-153 {
- color: #afd7ff;
-}
-
-.terminal .xterm-bg-color-153 {
- background-color: #afd7ff;
-}
-
-.terminal .xterm-color-154 {
- color: #afff00;
-}
-
-.terminal .xterm-bg-color-154 {
- background-color: #afff00;
-}
-
-.terminal .xterm-color-155 {
- color: #afff5f;
-}
-
-.terminal .xterm-bg-color-155 {
- background-color: #afff5f;
-}
-
-.terminal .xterm-color-156 {
- color: #afff87;
-}
-
-.terminal .xterm-bg-color-156 {
- background-color: #afff87;
-}
-
-.terminal .xterm-color-157 {
- color: #afffaf;
-}
-
-.terminal .xterm-bg-color-157 {
- background-color: #afffaf;
-}
-
-.terminal .xterm-color-158 {
- color: #afffd7;
-}
-
-.terminal .xterm-bg-color-158 {
- background-color: #afffd7;
-}
-
-.terminal .xterm-color-159 {
- color: #afffff;
-}
-
-.terminal .xterm-bg-color-159 {
- background-color: #afffff;
-}
-
-.terminal .xterm-color-160 {
- color: #d70000;
-}
-
-.terminal .xterm-bg-color-160 {
- background-color: #d70000;
-}
-
-.terminal .xterm-color-161 {
- color: #d7005f;
-}
-
-.terminal .xterm-bg-color-161 {
- background-color: #d7005f;
-}
-
-.terminal .xterm-color-162 {
- color: #d70087;
-}
-
-.terminal .xterm-bg-color-162 {
- background-color: #d70087;
-}
-
-.terminal .xterm-color-163 {
- color: #d700af;
-}
-
-.terminal .xterm-bg-color-163 {
- background-color: #d700af;
-}
-
-.terminal .xterm-color-164 {
- color: #d700d7;
-}
-
-.terminal .xterm-bg-color-164 {
- background-color: #d700d7;
-}
-
-.terminal .xterm-color-165 {
- color: #d700ff;
-}
-
-.terminal .xterm-bg-color-165 {
- background-color: #d700ff;
-}
-
-.terminal .xterm-color-166 {
- color: #d75f00;
-}
-
-.terminal .xterm-bg-color-166 {
- background-color: #d75f00;
-}
-
-.terminal .xterm-color-167 {
- color: #d75f5f;
-}
-
-.terminal .xterm-bg-color-167 {
- background-color: #d75f5f;
-}
-
-.terminal .xterm-color-168 {
- color: #d75f87;
-}
-
-.terminal .xterm-bg-color-168 {
- background-color: #d75f87;
-}
-
-.terminal .xterm-color-169 {
- color: #d75faf;
-}
-
-.terminal .xterm-bg-color-169 {
- background-color: #d75faf;
-}
-
-.terminal .xterm-color-170 {
- color: #d75fd7;
-}
-
-.terminal .xterm-bg-color-170 {
- background-color: #d75fd7;
-}
-
-.terminal .xterm-color-171 {
- color: #d75fff;
-}
-
-.terminal .xterm-bg-color-171 {
- background-color: #d75fff;
-}
-
-.terminal .xterm-color-172 {
- color: #d78700;
-}
-
-.terminal .xterm-bg-color-172 {
- background-color: #d78700;
-}
-
-.terminal .xterm-color-173 {
- color: #d7875f;
-}
-
-.terminal .xterm-bg-color-173 {
- background-color: #d7875f;
-}
-
-.terminal .xterm-color-174 {
- color: #d78787;
-}
-
-.terminal .xterm-bg-color-174 {
- background-color: #d78787;
-}
-
-.terminal .xterm-color-175 {
- color: #d787af;
-}
-
-.terminal .xterm-bg-color-175 {
- background-color: #d787af;
-}
-
-.terminal .xterm-color-176 {
- color: #d787d7;
-}
-
-.terminal .xterm-bg-color-176 {
- background-color: #d787d7;
-}
-
-.terminal .xterm-color-177 {
- color: #d787ff;
-}
-
-.terminal .xterm-bg-color-177 {
- background-color: #d787ff;
-}
-
-.terminal .xterm-color-178 {
- color: #d7af00;
-}
-
-.terminal .xterm-bg-color-178 {
- background-color: #d7af00;
-}
-
-.terminal .xterm-color-179 {
- color: #d7af5f;
-}
-
-.terminal .xterm-bg-color-179 {
- background-color: #d7af5f;
-}
-
-.terminal .xterm-color-180 {
- color: #d7af87;
-}
-
-.terminal .xterm-bg-color-180 {
- background-color: #d7af87;
-}
-
-.terminal .xterm-color-181 {
- color: #d7afaf;
-}
-
-.terminal .xterm-bg-color-181 {
- background-color: #d7afaf;
-}
-
-.terminal .xterm-color-182 {
- color: #d7afd7;
-}
-
-.terminal .xterm-bg-color-182 {
- background-color: #d7afd7;
-}
-
-.terminal .xterm-color-183 {
- color: #d7afff;
-}
-
-.terminal .xterm-bg-color-183 {
- background-color: #d7afff;
-}
-
-.terminal .xterm-color-184 {
- color: #d7d700;
-}
-
-.terminal .xterm-bg-color-184 {
- background-color: #d7d700;
-}
-
-.terminal .xterm-color-185 {
- color: #d7d75f;
-}
-
-.terminal .xterm-bg-color-185 {
- background-color: #d7d75f;
-}
-
-.terminal .xterm-color-186 {
- color: #d7d787;
-}
-
-.terminal .xterm-bg-color-186 {
- background-color: #d7d787;
-}
-
-.terminal .xterm-color-187 {
- color: #d7d7af;
-}
-
-.terminal .xterm-bg-color-187 {
- background-color: #d7d7af;
-}
-
-.terminal .xterm-color-188 {
- color: #d7d7d7;
-}
-
-.terminal .xterm-bg-color-188 {
- background-color: #d7d7d7;
-}
-
-.terminal .xterm-color-189 {
- color: #d7d7ff;
-}
-
-.terminal .xterm-bg-color-189 {
- background-color: #d7d7ff;
-}
-
-.terminal .xterm-color-190 {
- color: #d7ff00;
-}
-
-.terminal .xterm-bg-color-190 {
- background-color: #d7ff00;
-}
-
-.terminal .xterm-color-191 {
- color: #d7ff5f;
-}
-
-.terminal .xterm-bg-color-191 {
- background-color: #d7ff5f;
-}
-
-.terminal .xterm-color-192 {
- color: #d7ff87;
-}
-
-.terminal .xterm-bg-color-192 {
- background-color: #d7ff87;
-}
-
-.terminal .xterm-color-193 {
- color: #d7ffaf;
-}
-
-.terminal .xterm-bg-color-193 {
- background-color: #d7ffaf;
-}
-
-.terminal .xterm-color-194 {
- color: #d7ffd7;
-}
-
-.terminal .xterm-bg-color-194 {
- background-color: #d7ffd7;
-}
-
-.terminal .xterm-color-195 {
- color: #d7ffff;
-}
-
-.terminal .xterm-bg-color-195 {
- background-color: #d7ffff;
-}
-
-.terminal .xterm-color-196 {
- color: #ff0000;
-}
-
-.terminal .xterm-bg-color-196 {
- background-color: #ff0000;
-}
-
-.terminal .xterm-color-197 {
- color: #ff005f;
-}
-
-.terminal .xterm-bg-color-197 {
- background-color: #ff005f;
-}
-
-.terminal .xterm-color-198 {
- color: #ff0087;
-}
-
-.terminal .xterm-bg-color-198 {
- background-color: #ff0087;
-}
-
-.terminal .xterm-color-199 {
- color: #ff00af;
-}
-
-.terminal .xterm-bg-color-199 {
- background-color: #ff00af;
-}
-
-.terminal .xterm-color-200 {
- color: #ff00d7;
-}
-
-.terminal .xterm-bg-color-200 {
- background-color: #ff00d7;
-}
-
-.terminal .xterm-color-201 {
- color: #ff00ff;
-}
-
-.terminal .xterm-bg-color-201 {
- background-color: #ff00ff;
-}
-
-.terminal .xterm-color-202 {
- color: #ff5f00;
-}
-
-.terminal .xterm-bg-color-202 {
- background-color: #ff5f00;
-}
-
-.terminal .xterm-color-203 {
- color: #ff5f5f;
-}
-
-.terminal .xterm-bg-color-203 {
- background-color: #ff5f5f;
-}
-
-.terminal .xterm-color-204 {
- color: #ff5f87;
-}
-
-.terminal .xterm-bg-color-204 {
- background-color: #ff5f87;
-}
-
-.terminal .xterm-color-205 {
- color: #ff5faf;
-}
-
-.terminal .xterm-bg-color-205 {
- background-color: #ff5faf;
-}
-
-.terminal .xterm-color-206 {
- color: #ff5fd7;
-}
-
-.terminal .xterm-bg-color-206 {
- background-color: #ff5fd7;
-}
-
-.terminal .xterm-color-207 {
- color: #ff5fff;
-}
-
-.terminal .xterm-bg-color-207 {
- background-color: #ff5fff;
-}
-
-.terminal .xterm-color-208 {
- color: #ff8700;
-}
-
-.terminal .xterm-bg-color-208 {
- background-color: #ff8700;
-}
-
-.terminal .xterm-color-209 {
- color: #ff875f;
-}
-
-.terminal .xterm-bg-color-209 {
- background-color: #ff875f;
-}
-
-.terminal .xterm-color-210 {
- color: #ff8787;
-}
-
-.terminal .xterm-bg-color-210 {
- background-color: #ff8787;
-}
-
-.terminal .xterm-color-211 {
- color: #ff87af;
-}
-
-.terminal .xterm-bg-color-211 {
- background-color: #ff87af;
-}
-
-.terminal .xterm-color-212 {
- color: #ff87d7;
-}
-
-.terminal .xterm-bg-color-212 {
- background-color: #ff87d7;
-}
-
-.terminal .xterm-color-213 {
- color: #ff87ff;
-}
-
-.terminal .xterm-bg-color-213 {
- background-color: #ff87ff;
-}
-
-.terminal .xterm-color-214 {
- color: #ffaf00;
-}
-
-.terminal .xterm-bg-color-214 {
- background-color: #ffaf00;
-}
-
-.terminal .xterm-color-215 {
- color: #ffaf5f;
-}
-
-.terminal .xterm-bg-color-215 {
- background-color: #ffaf5f;
-}
-
-.terminal .xterm-color-216 {
- color: #ffaf87;
-}
-
-.terminal .xterm-bg-color-216 {
- background-color: #ffaf87;
-}
-
-.terminal .xterm-color-217 {
- color: #ffafaf;
-}
-
-.terminal .xterm-bg-color-217 {
- background-color: #ffafaf;
-}
-
-.terminal .xterm-color-218 {
- color: #ffafd7;
-}
-
-.terminal .xterm-bg-color-218 {
- background-color: #ffafd7;
-}
-
-.terminal .xterm-color-219 {
- color: #ffafff;
-}
-
-.terminal .xterm-bg-color-219 {
- background-color: #ffafff;
-}
-
-.terminal .xterm-color-220 {
- color: #ffd700;
-}
-
-.terminal .xterm-bg-color-220 {
- background-color: #ffd700;
-}
-
-.terminal .xterm-color-221 {
- color: #ffd75f;
-}
-
-.terminal .xterm-bg-color-221 {
- background-color: #ffd75f;
-}
-
-.terminal .xterm-color-222 {
- color: #ffd787;
-}
-
-.terminal .xterm-bg-color-222 {
- background-color: #ffd787;
-}
-
-.terminal .xterm-color-223 {
- color: #ffd7af;
-}
-
-.terminal .xterm-bg-color-223 {
- background-color: #ffd7af;
-}
-
-.terminal .xterm-color-224 {
- color: #ffd7d7;
-}
-
-.terminal .xterm-bg-color-224 {
- background-color: #ffd7d7;
-}
-
-.terminal .xterm-color-225 {
- color: #ffd7ff;
-}
-
-.terminal .xterm-bg-color-225 {
- background-color: #ffd7ff;
-}
-
-.terminal .xterm-color-226 {
- color: #ffff00;
-}
-
-.terminal .xterm-bg-color-226 {
- background-color: #ffff00;
-}
-
-.terminal .xterm-color-227 {
- color: #ffff5f;
-}
-
-.terminal .xterm-bg-color-227 {
- background-color: #ffff5f;
-}
-
-.terminal .xterm-color-228 {
- color: #ffff87;
-}
-
-.terminal .xterm-bg-color-228 {
- background-color: #ffff87;
-}
-
-.terminal .xterm-color-229 {
- color: #ffffaf;
-}
-
-.terminal .xterm-bg-color-229 {
- background-color: #ffffaf;
-}
-
-.terminal .xterm-color-230 {
- color: #ffffd7;
-}
-
-.terminal .xterm-bg-color-230 {
- background-color: #ffffd7;
-}
-
-.terminal .xterm-color-231 {
- color: #ffffff;
-}
-
-.terminal .xterm-bg-color-231 {
- background-color: #ffffff;
-}
-
-.terminal .xterm-color-232 {
- color: #080808;
-}
-
-.terminal .xterm-bg-color-232 {
- background-color: #080808;
-}
-
-.terminal .xterm-color-233 {
- color: #121212;
-}
-
-.terminal .xterm-bg-color-233 {
- background-color: #121212;
-}
-
-.terminal .xterm-color-234 {
- color: #1c1c1c;
-}
-
-.terminal .xterm-bg-color-234 {
- background-color: #1c1c1c;
-}
-
-.terminal .xterm-color-235 {
- color: #262626;
-}
-
-.terminal .xterm-bg-color-235 {
- background-color: #262626;
-}
-
-.terminal .xterm-color-236 {
- color: #303030;
-}
-
-.terminal .xterm-bg-color-236 {
- background-color: #303030;
-}
-
-.terminal .xterm-color-237 {
- color: #3a3a3a;
-}
-
-.terminal .xterm-bg-color-237 {
- background-color: #3a3a3a;
-}
-
-.terminal .xterm-color-238 {
- color: #444444;
-}
-
-.terminal .xterm-bg-color-238 {
- background-color: #444444;
-}
-
-.terminal .xterm-color-239 {
- color: #4e4e4e;
-}
-
-.terminal .xterm-bg-color-239 {
- background-color: #4e4e4e;
-}
-
-.terminal .xterm-color-240 {
- color: #585858;
-}
-
-.terminal .xterm-bg-color-240 {
- background-color: #585858;
-}
-
-.terminal .xterm-color-241 {
- color: #626262;
-}
-
-.terminal .xterm-bg-color-241 {
- background-color: #626262;
-}
-
-.terminal .xterm-color-242 {
- color: #6c6c6c;
-}
-
-.terminal .xterm-bg-color-242 {
- background-color: #6c6c6c;
-}
-
-.terminal .xterm-color-243 {
- color: #767676;
-}
-
-.terminal .xterm-bg-color-243 {
- background-color: #767676;
-}
-
-.terminal .xterm-color-244 {
- color: #808080;
-}
-
-.terminal .xterm-bg-color-244 {
- background-color: #808080;
-}
-
-.terminal .xterm-color-245 {
- color: #8a8a8a;
-}
-
-.terminal .xterm-bg-color-245 {
- background-color: #8a8a8a;
-}
-
-.terminal .xterm-color-246 {
- color: #949494;
-}
-
-.terminal .xterm-bg-color-246 {
- background-color: #949494;
-}
-
-.terminal .xterm-color-247 {
- color: #9e9e9e;
-}
-
-.terminal .xterm-bg-color-247 {
- background-color: #9e9e9e;
-}
-
-.terminal .xterm-color-248 {
- color: #a8a8a8;
-}
-
-.terminal .xterm-bg-color-248 {
- background-color: #a8a8a8;
-}
-
-.terminal .xterm-color-249 {
- color: #b2b2b2;
-}
-
-.terminal .xterm-bg-color-249 {
- background-color: #b2b2b2;
-}
-
-.terminal .xterm-color-250 {
- color: #bcbcbc;
-}
-
-.terminal .xterm-bg-color-250 {
- background-color: #bcbcbc;
-}
-
-.terminal .xterm-color-251 {
- color: #c6c6c6;
-}
-
-.terminal .xterm-bg-color-251 {
- background-color: #c6c6c6;
-}
-
-.terminal .xterm-color-252 {
- color: #d0d0d0;
-}
-
-.terminal .xterm-bg-color-252 {
- background-color: #d0d0d0;
-}
-
-.terminal .xterm-color-253 {
- color: #dadada;
-}
-
-.terminal .xterm-bg-color-253 {
- background-color: #dadada;
-}
-
-.terminal .xterm-color-254 {
- color: #e4e4e4;
-}
-
-.terminal .xterm-bg-color-254 {
- background-color: #e4e4e4;
-}
-
-.terminal .xterm-color-255 {
- color: #eeeeee;
-}
-
-.terminal .xterm-bg-color-255 {
- background-color: #eeeeee;
+ left: -9999px;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
}
diff --git a/apps/static/js/plugins/xterm/xterm.js b/apps/static/js/plugins/xterm/xterm.js
index 4b6f223a8..db90c5a3c 100644
--- a/apps/static/js/plugins/xterm/xterm.js
+++ b/apps/static/js/plugins/xterm/xterm.js
@@ -1,21 +1,267 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Terminal = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o rows) {
+ this._rowContainer.removeChild(this._rowElements.pop());
+ }
+ this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener);
+ this._refreshRowsDimensions();
+ };
+ AccessibilityManager.prototype._createAccessibilityTreeNode = function () {
+ var element = document.createElement('div');
+ element.setAttribute('role', 'listitem');
+ element.tabIndex = -1;
+ this._refreshRowDimensions(element);
+ return element;
+ };
+ AccessibilityManager.prototype._onTab = function (spaceCount) {
+ for (var i = 0; i < spaceCount; i++) {
+ this._onChar(' ');
+ }
+ };
+ AccessibilityManager.prototype._onChar = function (char) {
+ var _this = this;
+ if (this._liveRegionLineCount < MAX_ROWS_TO_READ + 1) {
+ if (this._charsToConsume.length > 0) {
+ var shiftedChar = this._charsToConsume.shift();
+ if (shiftedChar !== char) {
+ this._announceCharacter(char);
+ }
+ }
+ else {
+ this._announceCharacter(char);
+ }
+ if (char === '\n') {
+ this._liveRegionLineCount++;
+ if (this._liveRegionLineCount === MAX_ROWS_TO_READ + 1) {
+ this._liveRegion.textContent += Strings.tooMuchOutput;
+ }
+ }
+ if (Browser_1.isMac) {
+ if (this._liveRegion.textContent && this._liveRegion.textContent.length > 0 && !this._liveRegion.parentNode) {
+ setTimeout(function () {
+ _this._accessibilityTreeRoot.appendChild(_this._liveRegion);
+ }, 0);
+ }
+ }
+ }
+ };
+ AccessibilityManager.prototype._clearLiveRegion = function () {
+ this._liveRegion.textContent = '';
+ this._liveRegionLineCount = 0;
+ if (Browser_1.isMac) {
+ if (this._liveRegion.parentNode) {
+ this._accessibilityTreeRoot.removeChild(this._liveRegion);
+ }
+ }
+ };
+ AccessibilityManager.prototype._onKey = function (keyChar) {
+ this._clearLiveRegion();
+ this._charsToConsume.push(keyChar);
+ };
+ AccessibilityManager.prototype._refreshRows = function (start, end) {
+ this._renderRowsDebouncer.refresh(start, end);
+ };
+ AccessibilityManager.prototype._renderRows = function (start, end) {
+ var buffer = this._terminal.buffer;
+ var setSize = buffer.lines.length.toString();
+ for (var i = start; i <= end; i++) {
+ var lineData = buffer.translateBufferLineToString(buffer.ydisp + i, true);
+ var posInSet = (buffer.ydisp + i + 1).toString();
+ var element = this._rowElements[i];
+ element.textContent = lineData.length === 0 ? Strings.blankLine : lineData;
+ element.setAttribute('aria-posinset', posInSet);
+ element.setAttribute('aria-setsize', setSize);
+ }
+ };
+ AccessibilityManager.prototype._refreshRowsDimensions = function () {
+ if (!this._terminal.renderer.dimensions.actualCellHeight) {
+ return;
+ }
+ for (var i = 0; i < this._terminal.rows; i++) {
+ this._refreshRowDimensions(this._rowElements[i]);
+ }
+ };
+ AccessibilityManager.prototype._refreshRowDimensions = function (element) {
+ element.style.height = this._terminal.renderer.dimensions.actualCellHeight + "px";
+ };
+ AccessibilityManager.prototype._announceCharacter = function (char) {
+ if (char === ' ') {
+ this._liveRegion.innerHTML += ' ';
+ }
+ else {
+ this._liveRegion.textContent += char;
+ }
+ };
+ return AccessibilityManager;
+}(Lifecycle_2.Disposable));
+exports.AccessibilityManager = AccessibilityManager;
+
+},{"./Strings":13,"./common/Lifecycle":17,"./shared/utils/Browser":44,"./ui/Lifecycle":46,"./ui/RenderDebouncer":48}],2:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var CircularList_1 = require("./common/CircularList");
+var EventEmitter_1 = require("./EventEmitter");
+exports.DEFAULT_ATTR = (0 << 18) | (257 << 9) | (256 << 0);
+exports.CHAR_DATA_ATTR_INDEX = 0;
+exports.CHAR_DATA_CHAR_INDEX = 1;
+exports.CHAR_DATA_WIDTH_INDEX = 2;
+exports.CHAR_DATA_CODE_INDEX = 3;
+exports.MAX_BUFFER_SIZE = 4294967295;
var Buffer = (function () {
- function Buffer(_terminal) {
+ function Buffer(_terminal, _hasScrollback) {
this._terminal = _terminal;
+ this._hasScrollback = _hasScrollback;
+ this.markers = [];
this.clear();
}
- Object.defineProperty(Buffer.prototype, "lines", {
+ Object.defineProperty(Buffer.prototype, "hasScrollback", {
get: function () {
- return this._lines;
+ return this._hasScrollback && this.lines.maxLength > this._terminal.rows;
},
enumerable: true,
configurable: true
});
+ Object.defineProperty(Buffer.prototype, "isCursorInViewport", {
+ get: function () {
+ var absoluteY = this.ybase + this.y;
+ var relativeY = absoluteY - this.ydisp;
+ return (relativeY >= 0 && relativeY < this._terminal.rows);
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Buffer.prototype._getCorrectBufferLength = function (rows) {
+ if (!this._hasScrollback) {
+ return rows;
+ }
+ var correctBufferLength = rows + this._terminal.options.scrollback;
+ return correctBufferLength > exports.MAX_BUFFER_SIZE ? exports.MAX_BUFFER_SIZE : correctBufferLength;
+ };
Buffer.prototype.fillViewportRows = function () {
- if (this._lines.length === 0) {
+ if (this.lines.length === 0) {
var i = this._terminal.rows;
while (i--) {
this.lines.push(this._terminal.blankLine());
@@ -27,76 +273,209 @@ var Buffer = (function () {
this.ybase = 0;
this.y = 0;
this.x = 0;
- this.scrollBottom = 0;
+ this.lines = new CircularList_1.CircularList(this._getCorrectBufferLength(this._terminal.rows));
this.scrollTop = 0;
- this.tabs = {};
- this._lines = new CircularList_1.CircularList(this._terminal.scrollback);
this.scrollBottom = this._terminal.rows - 1;
+ this.setupTabStops();
};
Buffer.prototype.resize = function (newCols, newRows) {
- if (this._lines.length === 0) {
- return;
+ var newMaxLength = this._getCorrectBufferLength(newRows);
+ if (newMaxLength > this.lines.maxLength) {
+ this.lines.maxLength = newMaxLength;
}
- if (this._terminal.cols < newCols) {
- var ch = [this._terminal.defAttr, ' ', 1];
- for (var i = 0; i < this._lines.length; i++) {
- if (this._lines.get(i) === undefined) {
- this._lines.set(i, this._terminal.blankLine(undefined, undefined, newCols));
+ if (this.lines.length > 0) {
+ if (this._terminal.cols < newCols) {
+ var ch = [exports.DEFAULT_ATTR, ' ', 1, 32];
+ for (var i = 0; i < this.lines.length; i++) {
+ while (this.lines.get(i).length < newCols) {
+ this.lines.get(i).push(ch);
+ }
}
- while (this._lines.get(i).length < newCols) {
- this._lines.get(i).push(ch);
+ }
+ var addToY = 0;
+ if (this._terminal.rows < newRows) {
+ for (var y = this._terminal.rows; y < newRows; y++) {
+ if (this.lines.length < newRows + this.ybase) {
+ if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
+ this.ybase--;
+ addToY++;
+ if (this.ydisp > 0) {
+ this.ydisp--;
+ }
+ }
+ else {
+ this.lines.push(this._terminal.blankLine(undefined, undefined, newCols));
+ }
+ }
+ }
+ }
+ else {
+ for (var y = this._terminal.rows; y > newRows; y--) {
+ if (this.lines.length > newRows + this.ybase) {
+ if (this.lines.length > this.ybase + this.y + 1) {
+ this.lines.pop();
+ }
+ else {
+ this.ybase++;
+ this.ydisp++;
+ }
+ }
+ }
+ }
+ if (newMaxLength < this.lines.maxLength) {
+ var amountToTrim = this.lines.length - newMaxLength;
+ if (amountToTrim > 0) {
+ this.lines.trimStart(amountToTrim);
+ this.ybase = Math.max(this.ybase - amountToTrim, 0);
+ this.ydisp = Math.max(this.ydisp - amountToTrim, 0);
+ }
+ this.lines.maxLength = newMaxLength;
+ }
+ this.x = Math.min(this.x, newCols - 1);
+ this.y = Math.min(this.y, newRows - 1);
+ if (addToY) {
+ this.y += addToY;
+ }
+ this.savedY = Math.min(this.savedY, newRows - 1);
+ this.savedX = Math.min(this.savedX, newCols - 1);
+ this.scrollTop = 0;
+ }
+ this.scrollBottom = newRows - 1;
+ };
+ Buffer.prototype.translateBufferLineToString = function (lineIndex, trimRight, startCol, endCol) {
+ if (startCol === void 0) { startCol = 0; }
+ if (endCol === void 0) { endCol = null; }
+ var lineString = '';
+ var line = this.lines.get(lineIndex);
+ if (!line) {
+ return '';
+ }
+ var startIndex = startCol;
+ if (endCol === null) {
+ endCol = line.length;
+ }
+ var endIndex = endCol;
+ for (var i = 0; i < line.length; i++) {
+ var char = line[i];
+ lineString += char[exports.CHAR_DATA_CHAR_INDEX];
+ if (char[exports.CHAR_DATA_WIDTH_INDEX] === 0) {
+ if (startCol >= i) {
+ startIndex--;
+ }
+ if (endCol > i) {
+ endIndex--;
+ }
+ }
+ else {
+ if (char[exports.CHAR_DATA_CHAR_INDEX].length > 1) {
+ if (startCol > i) {
+ startIndex += char[exports.CHAR_DATA_CHAR_INDEX].length - 1;
+ }
+ if (endCol > i) {
+ endIndex += char[exports.CHAR_DATA_CHAR_INDEX].length - 1;
+ }
}
}
}
- var addToY = 0;
- if (this._terminal.rows < newRows) {
- for (var y = this._terminal.rows; y < newRows; y++) {
- if (this._lines.length < newRows + this.ybase) {
- if (this.ybase > 0 && this._lines.length <= this.ybase + this.y + addToY + 1) {
- this.ybase--;
- addToY++;
- if (this.ydisp > 0) {
- this.ydisp--;
- }
- }
- else {
- this._lines.push(this._terminal.blankLine(undefined, undefined, newCols));
- }
- }
+ if (trimRight) {
+ var rightWhitespaceIndex = lineString.search(/\s+$/);
+ if (rightWhitespaceIndex !== -1) {
+ endIndex = Math.min(endIndex, rightWhitespaceIndex);
+ }
+ if (endIndex <= startIndex) {
+ return '';
+ }
+ }
+ return lineString.substring(startIndex, endIndex);
+ };
+ Buffer.prototype.getWrappedRangeForLine = function (y) {
+ var first = y;
+ var last = y;
+ while (first > 0 && this.lines.get(first).isWrapped) {
+ first--;
+ }
+ while (last + 1 < this.lines.length && this.lines.get(last + 1).isWrapped) {
+ last++;
+ }
+ return { first: first, last: last };
+ };
+ Buffer.prototype.setupTabStops = function (i) {
+ if (i != null) {
+ if (!this.tabs[i]) {
+ i = this.prevStop(i);
}
}
else {
- for (var y = this._terminal.rows; y > newRows; y--) {
- if (this._lines.length > newRows + this.ybase) {
- if (this._lines.length > this.ybase + this.y + 1) {
- this._lines.pop();
- }
- else {
- this.ybase++;
- this.ydisp++;
- }
- }
+ this.tabs = {};
+ i = 0;
+ }
+ for (; i < this._terminal.cols; i += this._terminal.options.tabStopWidth) {
+ this.tabs[i] = true;
+ }
+ };
+ Buffer.prototype.prevStop = function (x) {
+ if (x == null) {
+ x = this.x;
+ }
+ while (!this.tabs[--x] && x > 0)
+ ;
+ return x >= this._terminal.cols ? this._terminal.cols - 1 : x < 0 ? 0 : x;
+ };
+ Buffer.prototype.nextStop = function (x) {
+ if (x == null) {
+ x = this.x;
+ }
+ while (!this.tabs[++x] && x < this._terminal.cols)
+ ;
+ return x >= this._terminal.cols ? this._terminal.cols - 1 : x < 0 ? 0 : x;
+ };
+ Buffer.prototype.addMarker = function (y) {
+ var _this = this;
+ var marker = new Marker(y);
+ this.markers.push(marker);
+ marker.register(this.lines.addDisposableListener('trim', function (amount) {
+ marker.line -= amount;
+ if (marker.line < 0) {
+ marker.dispose();
}
- }
- if (this.y >= newRows) {
- this.y = newRows - 1;
- }
- if (addToY) {
- this.y += addToY;
- }
- if (this.x >= newCols) {
- this.x = newCols - 1;
- }
- this.scrollTop = 0;
- this.scrollBottom = newRows - 1;
+ }));
+ marker.register(marker.addDisposableListener('dispose', function () { return _this._removeMarker(marker); }));
+ return marker;
+ };
+ Buffer.prototype._removeMarker = function (marker) {
+ this.markers.splice(this.markers.indexOf(marker), 1);
};
return Buffer;
}());
exports.Buffer = Buffer;
+var Marker = (function (_super) {
+ __extends(Marker, _super);
+ function Marker(line) {
+ var _this = _super.call(this) || this;
+ _this.line = line;
+ _this._id = Marker._nextId++;
+ _this.isDisposed = false;
+ return _this;
+ }
+ Object.defineProperty(Marker.prototype, "id", {
+ get: function () { return this._id; },
+ enumerable: true,
+ configurable: true
+ });
+ Marker.prototype.dispose = function () {
+ if (this.isDisposed) {
+ return;
+ }
+ this.isDisposed = true;
+ this.emit('dispose');
+ _super.prototype.dispose.call(this);
+ };
+ Marker._nextId = 1;
+ return Marker;
+}(EventEmitter_1.EventEmitter));
+exports.Marker = Marker;
-
-
-},{"./utils/CircularList":18}],2:[function(require,module,exports){
+},{"./EventEmitter":7,"./common/CircularList":16}],3:[function(require,module,exports){
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
@@ -116,10 +495,11 @@ var BufferSet = (function (_super) {
function BufferSet(_terminal) {
var _this = _super.call(this) || this;
_this._terminal = _terminal;
- _this._normal = new Buffer_1.Buffer(_this._terminal);
+ _this._normal = new Buffer_1.Buffer(_this._terminal, true);
_this._normal.fillViewportRows();
- _this._alt = new Buffer_1.Buffer(_this._terminal);
+ _this._alt = new Buffer_1.Buffer(_this._terminal, false);
_this._activeBuffer = _this._normal;
+ _this.setupTabStops();
return _this;
}
Object.defineProperty(BufferSet.prototype, "alt", {
@@ -144,26 +524,4415 @@ var BufferSet = (function (_super) {
configurable: true
});
BufferSet.prototype.activateNormalBuffer = function () {
+ if (this._activeBuffer === this._normal) {
+ return;
+ }
this._alt.clear();
this._activeBuffer = this._normal;
- this.emit('activate', this._normal);
+ this.emit('activate', {
+ activeBuffer: this._normal,
+ inactiveBuffer: this._alt
+ });
};
BufferSet.prototype.activateAltBuffer = function () {
+ if (this._activeBuffer === this._alt) {
+ return;
+ }
this._alt.fillViewportRows();
this._activeBuffer = this._alt;
- this.emit('activate', this._alt);
+ this.emit('activate', {
+ activeBuffer: this._alt,
+ inactiveBuffer: this._normal
+ });
};
BufferSet.prototype.resize = function (newCols, newRows) {
this._normal.resize(newCols, newRows);
this._alt.resize(newCols, newRows);
};
+ BufferSet.prototype.setupTabStops = function (i) {
+ this._normal.setupTabStops(i);
+ this._alt.setupTabStops(i);
+ };
return BufferSet;
}(EventEmitter_1.EventEmitter));
exports.BufferSet = BufferSet;
+},{"./Buffer":2,"./EventEmitter":7}],4:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.wcwidth = (function (opts) {
+ var COMBINING_BMP = [
+ [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489],
+ [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2],
+ [0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603],
+ [0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670],
+ [0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED],
+ [0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A],
+ [0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902],
+ [0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D],
+ [0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981],
+ [0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD],
+ [0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C],
+ [0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D],
+ [0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC],
+ [0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD],
+ [0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C],
+ [0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D],
+ [0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0],
+ [0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48],
+ [0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC],
+ [0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD],
+ [0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D],
+ [0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6],
+ [0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E],
+ [0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC],
+ [0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35],
+ [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E],
+ [0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97],
+ [0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030],
+ [0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039],
+ [0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F],
+ [0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753],
+ [0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD],
+ [0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD],
+ [0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922],
+ [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B],
+ [0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34],
+ [0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42],
+ [0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF],
+ [0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063],
+ [0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F],
+ [0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B],
+ [0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F],
+ [0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB]
+ ];
+ var COMBINING_HIGH = [
+ [0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F],
+ [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169],
+ [0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD],
+ [0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F],
+ [0xE0100, 0xE01EF]
+ ];
+ function bisearch(ucs, data) {
+ var min = 0;
+ var max = data.length - 1;
+ var mid;
+ if (ucs < data[0][0] || ucs > data[max][1]) {
+ return false;
+ }
+ while (max >= min) {
+ mid = (min + max) >> 1;
+ if (ucs > data[mid][1]) {
+ min = mid + 1;
+ }
+ else if (ucs < data[mid][0]) {
+ max = mid - 1;
+ }
+ else {
+ return true;
+ }
+ }
+ return false;
+ }
+ function wcwidthBMP(ucs) {
+ if (ucs === 0) {
+ return opts.nul;
+ }
+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) {
+ return opts.control;
+ }
+ if (bisearch(ucs, COMBINING_BMP)) {
+ return 0;
+ }
+ if (isWideBMP(ucs)) {
+ return 2;
+ }
+ return 1;
+ }
+ function isWideBMP(ucs) {
+ return (ucs >= 0x1100 && (ucs <= 0x115f ||
+ ucs === 0x2329 ||
+ ucs === 0x232a ||
+ (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs !== 0x303f) ||
+ (ucs >= 0xac00 && ucs <= 0xd7a3) ||
+ (ucs >= 0xf900 && ucs <= 0xfaff) ||
+ (ucs >= 0xfe10 && ucs <= 0xfe19) ||
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) ||
+ (ucs >= 0xff00 && ucs <= 0xff60) ||
+ (ucs >= 0xffe0 && ucs <= 0xffe6)));
+ }
+ function wcwidthHigh(ucs) {
+ if (bisearch(ucs, COMBINING_HIGH)) {
+ return 0;
+ }
+ if ((ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd)) {
+ return 2;
+ }
+ return 1;
+ }
+ var control = opts.control | 0;
+ var table = null;
+ function initTable() {
+ var CODEPOINTS = 65536;
+ var BITWIDTH = 2;
+ var ITEMSIZE = 32;
+ var CONTAINERSIZE = CODEPOINTS * BITWIDTH / ITEMSIZE;
+ var CODEPOINTS_PER_ITEM = ITEMSIZE / BITWIDTH;
+ table = (typeof Uint32Array === 'undefined')
+ ? new Array(CONTAINERSIZE)
+ : new Uint32Array(CONTAINERSIZE);
+ for (var i = 0; i < CONTAINERSIZE; ++i) {
+ var num = 0;
+ var pos = CODEPOINTS_PER_ITEM;
+ while (pos--) {
+ num = (num << 2) | wcwidthBMP(CODEPOINTS_PER_ITEM * i + pos);
+ }
+ table[i] = num;
+ }
+ return table;
+ }
+ return function (num) {
+ num = num | 0;
+ if (num < 32) {
+ return control | 0;
+ }
+ if (num < 127) {
+ return 1;
+ }
+ var t = table || initTable();
+ if (num < 65536) {
+ return t[num >> 4] >> ((num & 15) << 1) & 3;
+ }
+ return wcwidthHigh(num);
+ };
+})({ nul: 0, control: 0 });
+},{}],5:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var CompositionHelper = (function () {
+ function CompositionHelper(_textarea, _compositionView, _terminal) {
+ this._textarea = _textarea;
+ this._compositionView = _compositionView;
+ this._terminal = _terminal;
+ this._isComposing = false;
+ this._isSendingComposition = false;
+ this._compositionPosition = { start: null, end: null };
+ }
+ CompositionHelper.prototype.compositionstart = function () {
+ this._isComposing = true;
+ this._compositionPosition.start = this._textarea.value.length;
+ this._compositionView.textContent = '';
+ this._compositionView.classList.add('active');
+ };
+ CompositionHelper.prototype.compositionupdate = function (ev) {
+ var _this = this;
+ this._compositionView.textContent = ev.data;
+ this.updateCompositionElements();
+ setTimeout(function () {
+ _this._compositionPosition.end = _this._textarea.value.length;
+ }, 0);
+ };
+ CompositionHelper.prototype.compositionend = function () {
+ this._finalizeComposition(true);
+ };
+ CompositionHelper.prototype.keydown = function (ev) {
+ if (this._isComposing || this._isSendingComposition) {
+ if (ev.keyCode === 229) {
+ return false;
+ }
+ else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) {
+ return false;
+ }
+ this._finalizeComposition(false);
+ }
+ if (ev.keyCode === 229) {
+ this._handleAnyTextareaChanges();
+ return false;
+ }
+ return true;
+ };
+ CompositionHelper.prototype._finalizeComposition = function (waitForPropogation) {
+ var _this = this;
+ this._compositionView.classList.remove('active');
+ this._isComposing = false;
+ this._clearTextareaPosition();
+ if (!waitForPropogation) {
+ this._isSendingComposition = false;
+ var input = this._textarea.value.substring(this._compositionPosition.start, this._compositionPosition.end);
+ this._terminal.handler(input);
+ }
+ else {
+ var currentCompositionPosition_1 = {
+ start: this._compositionPosition.start,
+ end: this._compositionPosition.end
+ };
+ this._isSendingComposition = true;
+ setTimeout(function () {
+ if (_this._isSendingComposition) {
+ _this._isSendingComposition = false;
+ var input = void 0;
+ if (_this._isComposing) {
+ input = _this._textarea.value.substring(currentCompositionPosition_1.start, currentCompositionPosition_1.end);
+ }
+ else {
+ input = _this._textarea.value.substring(currentCompositionPosition_1.start);
+ }
+ _this._terminal.handler(input);
+ }
+ }, 0);
+ }
+ };
+ CompositionHelper.prototype._handleAnyTextareaChanges = function () {
+ var _this = this;
+ var oldValue = this._textarea.value;
+ setTimeout(function () {
+ if (!_this._isComposing) {
+ var newValue = _this._textarea.value;
+ var diff = newValue.replace(oldValue, '');
+ if (diff.length > 0) {
+ _this._terminal.handler(diff);
+ }
+ }
+ }, 0);
+ };
+ CompositionHelper.prototype.updateCompositionElements = function (dontRecurse) {
+ var _this = this;
+ if (!this._isComposing) {
+ return;
+ }
+ if (this._terminal.buffer.isCursorInViewport) {
+ var cellHeight = Math.ceil(this._terminal.charMeasure.height * this._terminal.options.lineHeight);
+ var cursorTop = this._terminal.buffer.y * cellHeight;
+ var cursorLeft = this._terminal.buffer.x * this._terminal.charMeasure.width;
+ this._compositionView.style.left = cursorLeft + 'px';
+ this._compositionView.style.top = cursorTop + 'px';
+ this._compositionView.style.height = cellHeight + 'px';
+ this._compositionView.style.lineHeight = cellHeight + 'px';
+ var compositionViewBounds = this._compositionView.getBoundingClientRect();
+ this._textarea.style.left = cursorLeft + 'px';
+ this._textarea.style.top = cursorTop + 'px';
+ this._textarea.style.width = compositionViewBounds.width + 'px';
+ this._textarea.style.height = compositionViewBounds.height + 'px';
+ this._textarea.style.lineHeight = compositionViewBounds.height + 'px';
+ }
+ if (!dontRecurse) {
+ setTimeout(function () { return _this.updateCompositionElements(true); }, 0);
+ }
+ };
+ CompositionHelper.prototype._clearTextareaPosition = function () {
+ this._textarea.style.left = '';
+ this._textarea.style.top = '';
+ };
+ return CompositionHelper;
+}());
+exports.CompositionHelper = CompositionHelper;
-},{"./Buffer":1,"./EventEmitter":6}],3:[function(require,module,exports){
+},{}],6:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Lifecycle_1 = require("./common/Lifecycle");
+function r(low, high) {
+ var c = high - low;
+ var arr = new Array(c);
+ while (c--) {
+ arr[c] = --high;
+ }
+ return arr;
+}
+var TransitionTable = (function () {
+ function TransitionTable(length) {
+ this.table = (typeof Uint8Array === 'undefined')
+ ? new Array(length)
+ : new Uint8Array(length);
+ }
+ TransitionTable.prototype.add = function (code, state, action, next) {
+ this.table[state << 8 | code] = ((action | 0) << 4) | ((next === undefined) ? state : next);
+ };
+ TransitionTable.prototype.addMany = function (codes, state, action, next) {
+ for (var i = 0; i < codes.length; i++) {
+ this.add(codes[i], state, action, next);
+ }
+ };
+ return TransitionTable;
+}());
+exports.TransitionTable = TransitionTable;
+var PRINTABLES = r(0x20, 0x7f);
+var EXECUTABLES = r(0x00, 0x18);
+EXECUTABLES.push(0x19);
+EXECUTABLES.concat(r(0x1c, 0x20));
+var DEFAULT_TRANSITION = 1 << 4 | 0;
+exports.VT500_TRANSITION_TABLE = (function () {
+ var table = new TransitionTable(4095);
+ var states = r(0, 13 + 1);
+ var state;
+ for (state in states) {
+ for (var code = 0; code < 160; ++code) {
+ table.add(code, state, 1, 0);
+ }
+ }
+ table.addMany(PRINTABLES, 0, 2, 0);
+ for (state in states) {
+ table.addMany([0x18, 0x1a, 0x99, 0x9a], state, 3, 0);
+ table.addMany(r(0x80, 0x90), state, 3, 0);
+ table.addMany(r(0x90, 0x98), state, 3, 0);
+ table.add(0x9c, state, 0, 0);
+ table.add(0x1b, state, 11, 1);
+ table.add(0x9d, state, 4, 8);
+ table.addMany([0x98, 0x9e, 0x9f], state, 0, 7);
+ table.add(0x9b, state, 11, 3);
+ table.add(0x90, state, 11, 9);
+ }
+ table.addMany(EXECUTABLES, 0, 3, 0);
+ table.addMany(EXECUTABLES, 1, 3, 1);
+ table.add(0x7f, 1, 0, 1);
+ table.addMany(EXECUTABLES, 8, 0, 8);
+ table.addMany(EXECUTABLES, 3, 3, 3);
+ table.add(0x7f, 3, 0, 3);
+ table.addMany(EXECUTABLES, 4, 3, 4);
+ table.add(0x7f, 4, 0, 4);
+ table.addMany(EXECUTABLES, 6, 3, 6);
+ table.addMany(EXECUTABLES, 5, 3, 5);
+ table.add(0x7f, 5, 0, 5);
+ table.addMany(EXECUTABLES, 2, 3, 2);
+ table.add(0x7f, 2, 0, 2);
+ table.add(0x5d, 1, 4, 8);
+ table.addMany(PRINTABLES, 8, 5, 8);
+ table.add(0x7f, 8, 5, 8);
+ table.addMany([0x9c, 0x1b, 0x18, 0x1a, 0x07], 8, 6, 0);
+ table.addMany(r(0x1c, 0x20), 8, 0, 8);
+ table.addMany([0x58, 0x5e, 0x5f], 1, 0, 7);
+ table.addMany(PRINTABLES, 7, 0, 7);
+ table.addMany(EXECUTABLES, 7, 0, 7);
+ table.add(0x9c, 7, 0, 0);
+ table.add(0x5b, 1, 11, 3);
+ table.addMany(r(0x40, 0x7f), 3, 7, 0);
+ table.addMany(r(0x30, 0x3a), 3, 8, 4);
+ table.add(0x3b, 3, 8, 4);
+ table.addMany([0x3c, 0x3d, 0x3e, 0x3f], 3, 9, 4);
+ table.addMany(r(0x30, 0x3a), 4, 8, 4);
+ table.add(0x3b, 4, 8, 4);
+ table.addMany(r(0x40, 0x7f), 4, 7, 0);
+ table.addMany([0x3a, 0x3c, 0x3d, 0x3e, 0x3f], 4, 0, 6);
+ table.addMany(r(0x20, 0x40), 6, 0, 6);
+ table.add(0x7f, 6, 0, 6);
+ table.addMany(r(0x40, 0x7f), 6, 0, 0);
+ table.add(0x3a, 3, 0, 6);
+ table.addMany(r(0x20, 0x30), 3, 9, 5);
+ table.addMany(r(0x20, 0x30), 5, 9, 5);
+ table.addMany(r(0x30, 0x40), 5, 0, 6);
+ table.addMany(r(0x40, 0x7f), 5, 7, 0);
+ table.addMany(r(0x20, 0x30), 4, 9, 5);
+ table.addMany(r(0x20, 0x30), 1, 9, 2);
+ table.addMany(r(0x20, 0x30), 2, 9, 2);
+ table.addMany(r(0x30, 0x7f), 2, 10, 0);
+ table.addMany(r(0x30, 0x50), 1, 10, 0);
+ table.addMany(r(0x51, 0x58), 1, 10, 0);
+ table.addMany([0x59, 0x5a, 0x5c], 1, 10, 0);
+ table.addMany(r(0x60, 0x7f), 1, 10, 0);
+ table.add(0x50, 1, 11, 9);
+ table.addMany(EXECUTABLES, 9, 0, 9);
+ table.add(0x7f, 9, 0, 9);
+ table.addMany(r(0x1c, 0x20), 9, 0, 9);
+ table.addMany(r(0x20, 0x30), 9, 9, 12);
+ table.add(0x3a, 9, 0, 11);
+ table.addMany(r(0x30, 0x3a), 9, 8, 10);
+ table.add(0x3b, 9, 8, 10);
+ table.addMany([0x3c, 0x3d, 0x3e, 0x3f], 9, 9, 10);
+ table.addMany(EXECUTABLES, 11, 0, 11);
+ table.addMany(r(0x20, 0x80), 11, 0, 11);
+ table.addMany(r(0x1c, 0x20), 11, 0, 11);
+ table.addMany(EXECUTABLES, 10, 0, 10);
+ table.add(0x7f, 10, 0, 10);
+ table.addMany(r(0x1c, 0x20), 10, 0, 10);
+ table.addMany(r(0x30, 0x3a), 10, 8, 10);
+ table.add(0x3b, 10, 8, 10);
+ table.addMany([0x3a, 0x3c, 0x3d, 0x3e, 0x3f], 10, 0, 11);
+ table.addMany(r(0x20, 0x30), 10, 9, 12);
+ table.addMany(EXECUTABLES, 12, 0, 12);
+ table.add(0x7f, 12, 0, 12);
+ table.addMany(r(0x1c, 0x20), 12, 0, 12);
+ table.addMany(r(0x20, 0x30), 12, 9, 12);
+ table.addMany(r(0x30, 0x40), 12, 0, 11);
+ table.addMany(r(0x40, 0x7f), 12, 12, 13);
+ table.addMany(r(0x40, 0x7f), 10, 12, 13);
+ table.addMany(r(0x40, 0x7f), 9, 12, 13);
+ table.addMany(EXECUTABLES, 13, 13, 13);
+ table.addMany(PRINTABLES, 13, 13, 13);
+ table.add(0x7f, 13, 0, 13);
+ table.addMany([0x1b, 0x9c], 13, 14, 0);
+ return table;
+})();
+var DcsDummy = (function () {
+ function DcsDummy() {
+ }
+ DcsDummy.prototype.hook = function (collect, params, flag) { };
+ DcsDummy.prototype.put = function (data, start, end) { };
+ DcsDummy.prototype.unhook = function () { };
+ return DcsDummy;
+}());
+var EscapeSequenceParser = (function (_super) {
+ __extends(EscapeSequenceParser, _super);
+ function EscapeSequenceParser(TRANSITIONS) {
+ if (TRANSITIONS === void 0) { TRANSITIONS = exports.VT500_TRANSITION_TABLE; }
+ var _this = _super.call(this) || this;
+ _this.TRANSITIONS = TRANSITIONS;
+ _this.initialState = 0;
+ _this.currentState = _this.initialState;
+ _this._osc = '';
+ _this._params = [0];
+ _this._collect = '';
+ _this._printHandlerFb = function (data, start, end) { };
+ _this._executeHandlerFb = function (code) { };
+ _this._csiHandlerFb = function (collect, params, flag) { };
+ _this._escHandlerFb = function (collect, flag) { };
+ _this._oscHandlerFb = function (identifier, data) { };
+ _this._dcsHandlerFb = new DcsDummy();
+ _this._errorHandlerFb = function (state) { return state; };
+ _this._printHandler = _this._printHandlerFb;
+ _this._executeHandlers = Object.create(null);
+ _this._csiHandlers = Object.create(null);
+ _this._escHandlers = Object.create(null);
+ _this._oscHandlers = Object.create(null);
+ _this._dcsHandlers = Object.create(null);
+ _this._activeDcsHandler = null;
+ _this._errorHandler = _this._errorHandlerFb;
+ return _this;
+ }
+ EscapeSequenceParser.prototype.dispose = function () {
+ this._printHandlerFb = null;
+ this._executeHandlerFb = null;
+ this._csiHandlerFb = null;
+ this._escHandlerFb = null;
+ this._oscHandlerFb = null;
+ this._dcsHandlerFb = null;
+ this._errorHandlerFb = null;
+ this._printHandler = null;
+ this._executeHandlers = null;
+ this._csiHandlers = null;
+ this._escHandlers = null;
+ this._oscHandlers = null;
+ this._dcsHandlers = null;
+ this._activeDcsHandler = null;
+ this._errorHandler = null;
+ };
+ EscapeSequenceParser.prototype.setPrintHandler = function (callback) {
+ this._printHandler = callback;
+ };
+ EscapeSequenceParser.prototype.clearPrintHandler = function () {
+ this._printHandler = this._printHandlerFb;
+ };
+ EscapeSequenceParser.prototype.setExecuteHandler = function (flag, callback) {
+ this._executeHandlers[flag.charCodeAt(0)] = callback;
+ };
+ EscapeSequenceParser.prototype.clearExecuteHandler = function (flag) {
+ if (this._executeHandlers[flag.charCodeAt(0)])
+ delete this._executeHandlers[flag.charCodeAt(0)];
+ };
+ EscapeSequenceParser.prototype.setExecuteHandlerFallback = function (callback) {
+ this._executeHandlerFb = callback;
+ };
+ EscapeSequenceParser.prototype.setCsiHandler = function (flag, callback) {
+ this._csiHandlers[flag.charCodeAt(0)] = callback;
+ };
+ EscapeSequenceParser.prototype.clearCsiHandler = function (flag) {
+ if (this._csiHandlers[flag.charCodeAt(0)])
+ delete this._csiHandlers[flag.charCodeAt(0)];
+ };
+ EscapeSequenceParser.prototype.setCsiHandlerFallback = function (callback) {
+ this._csiHandlerFb = callback;
+ };
+ EscapeSequenceParser.prototype.setEscHandler = function (collectAndFlag, callback) {
+ this._escHandlers[collectAndFlag] = callback;
+ };
+ EscapeSequenceParser.prototype.clearEscHandler = function (collectAndFlag) {
+ if (this._escHandlers[collectAndFlag])
+ delete this._escHandlers[collectAndFlag];
+ };
+ EscapeSequenceParser.prototype.setEscHandlerFallback = function (callback) {
+ this._escHandlerFb = callback;
+ };
+ EscapeSequenceParser.prototype.setOscHandler = function (ident, callback) {
+ this._oscHandlers[ident] = callback;
+ };
+ EscapeSequenceParser.prototype.clearOscHandler = function (ident) {
+ if (this._oscHandlers[ident])
+ delete this._oscHandlers[ident];
+ };
+ EscapeSequenceParser.prototype.setOscHandlerFallback = function (callback) {
+ this._oscHandlerFb = callback;
+ };
+ EscapeSequenceParser.prototype.setDcsHandler = function (collectAndFlag, handler) {
+ this._dcsHandlers[collectAndFlag] = handler;
+ };
+ EscapeSequenceParser.prototype.clearDcsHandler = function (collectAndFlag) {
+ if (this._dcsHandlers[collectAndFlag])
+ delete this._dcsHandlers[collectAndFlag];
+ };
+ EscapeSequenceParser.prototype.setDcsHandlerFallback = function (handler) {
+ this._dcsHandlerFb = handler;
+ };
+ EscapeSequenceParser.prototype.setErrorHandler = function (callback) {
+ this._errorHandler = callback;
+ };
+ EscapeSequenceParser.prototype.clearErrorHandler = function () {
+ this._errorHandler = this._errorHandlerFb;
+ };
+ EscapeSequenceParser.prototype.reset = function () {
+ this.currentState = this.initialState;
+ this._osc = '';
+ this._params = [0];
+ this._collect = '';
+ this._activeDcsHandler = null;
+ };
+ EscapeSequenceParser.prototype.parse = function (data) {
+ var code = 0;
+ var transition = 0;
+ var error = false;
+ var currentState = this.currentState;
+ var print = -1;
+ var dcs = -1;
+ var osc = this._osc;
+ var collect = this._collect;
+ var params = this._params;
+ var table = this.TRANSITIONS.table;
+ var dcsHandler = this._activeDcsHandler;
+ var callback = null;
+ var l = data.length;
+ for (var i = 0; i < l; ++i) {
+ code = data.charCodeAt(i);
+ if (currentState === 0 && code > 0x1f && code < 0x80) {
+ print = (~print) ? print : i;
+ do
+ code = data.charCodeAt(++i);
+ while (i < l && code > 0x1f && code < 0x80);
+ i--;
+ continue;
+ }
+ if (currentState === 4 && (code > 0x2f && code < 0x39)) {
+ params[params.length - 1] = params[params.length - 1] * 10 + code - 48;
+ continue;
+ }
+ transition = (code < 0xa0) ? (table[currentState << 8 | code]) : DEFAULT_TRANSITION;
+ switch (transition >> 4) {
+ case 2:
+ print = (~print) ? print : i;
+ break;
+ case 3:
+ if (~print) {
+ this._printHandler(data, print, i);
+ print = -1;
+ }
+ callback = this._executeHandlers[code];
+ if (callback)
+ callback();
+ else
+ this._executeHandlerFb(code);
+ break;
+ case 0:
+ if (~print) {
+ this._printHandler(data, print, i);
+ print = -1;
+ }
+ else if (~dcs) {
+ dcsHandler.put(data, dcs, i);
+ dcs = -1;
+ }
+ break;
+ case 1:
+ if (code > 0x9f) {
+ switch (currentState) {
+ case 0:
+ print = (~print) ? print : i;
+ break;
+ case 8:
+ osc += String.fromCharCode(code);
+ transition |= 8;
+ break;
+ case 6:
+ transition |= 6;
+ break;
+ case 11:
+ transition |= 11;
+ break;
+ case 13:
+ dcs = (~dcs) ? dcs : i;
+ transition |= 13;
+ break;
+ default:
+ error = true;
+ }
+ }
+ else {
+ error = true;
+ }
+ if (error) {
+ var inject = this._errorHandler({
+ position: i,
+ code: code,
+ currentState: currentState,
+ print: print,
+ dcs: dcs,
+ osc: osc,
+ collect: collect,
+ params: params,
+ abort: false
+ });
+ if (inject.abort)
+ return;
+ error = false;
+ }
+ break;
+ case 7:
+ callback = this._csiHandlers[code];
+ if (callback)
+ callback(params, collect);
+ else
+ this._csiHandlerFb(collect, params, code);
+ break;
+ case 8:
+ if (code === 0x3b)
+ params.push(0);
+ else
+ params[params.length - 1] = params[params.length - 1] * 10 + code - 48;
+ break;
+ case 9:
+ collect += String.fromCharCode(code);
+ break;
+ case 10:
+ callback = this._escHandlers[collect + String.fromCharCode(code)];
+ if (callback)
+ callback(collect, code);
+ else
+ this._escHandlerFb(collect, code);
+ break;
+ case 11:
+ if (~print) {
+ this._printHandler(data, print, i);
+ print = -1;
+ }
+ osc = '';
+ params = [0];
+ collect = '';
+ dcs = -1;
+ break;
+ case 12:
+ dcsHandler = this._dcsHandlers[collect + String.fromCharCode(code)];
+ if (!dcsHandler)
+ dcsHandler = this._dcsHandlerFb;
+ dcsHandler.hook(collect, params, code);
+ break;
+ case 13:
+ dcs = (~dcs) ? dcs : i;
+ break;
+ case 14:
+ if (dcsHandler) {
+ if (~dcs)
+ dcsHandler.put(data, dcs, i);
+ dcsHandler.unhook();
+ dcsHandler = null;
+ }
+ if (code === 0x1b)
+ transition |= 1;
+ osc = '';
+ params = [0];
+ collect = '';
+ dcs = -1;
+ break;
+ case 4:
+ if (~print) {
+ this._printHandler(data, print, i);
+ print = -1;
+ }
+ osc = '';
+ break;
+ case 5:
+ osc += data.charAt(i);
+ break;
+ case 6:
+ if (osc && code !== 0x18 && code !== 0x1a) {
+ var idx = osc.indexOf(';');
+ if (idx === -1) {
+ this._oscHandlerFb(-1, osc);
+ }
+ else {
+ var identifier = parseInt(osc.substring(0, idx));
+ var content = osc.substring(idx + 1);
+ callback = this._oscHandlers[identifier];
+ if (callback)
+ callback(content);
+ else
+ this._oscHandlerFb(identifier, content);
+ }
+ }
+ if (code === 0x1b)
+ transition |= 1;
+ osc = '';
+ params = [0];
+ collect = '';
+ dcs = -1;
+ break;
+ }
+ currentState = transition & 15;
+ }
+ if (currentState === 0 && ~print) {
+ this._printHandler(data, print, data.length);
+ }
+ else if (currentState === 13 && ~dcs && dcsHandler) {
+ dcsHandler.put(data, dcs, data.length);
+ }
+ this._osc = osc;
+ this._collect = collect;
+ this._params = params;
+ this._activeDcsHandler = dcsHandler;
+ this.currentState = currentState;
+ };
+ return EscapeSequenceParser;
+}(Lifecycle_1.Disposable));
+exports.EscapeSequenceParser = EscapeSequenceParser;
+
+},{"./common/Lifecycle":17}],7:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Lifecycle_1 = require("./common/Lifecycle");
+var EventEmitter = (function (_super) {
+ __extends(EventEmitter, _super);
+ function EventEmitter() {
+ var _this = _super.call(this) || this;
+ _this._events = _this._events || {};
+ return _this;
+ }
+ EventEmitter.prototype.on = function (type, listener) {
+ this._events[type] = this._events[type] || [];
+ this._events[type].push(listener);
+ };
+ EventEmitter.prototype.addDisposableListener = function (type, handler) {
+ var _this = this;
+ this.on(type, handler);
+ return {
+ dispose: function () {
+ if (!handler) {
+ return;
+ }
+ _this.off(type, handler);
+ handler = null;
+ }
+ };
+ };
+ EventEmitter.prototype.off = function (type, listener) {
+ if (!this._events[type]) {
+ return;
+ }
+ var obj = this._events[type];
+ var i = obj.length;
+ while (i--) {
+ if (obj[i] === listener) {
+ obj.splice(i, 1);
+ return;
+ }
+ }
+ };
+ EventEmitter.prototype.removeAllListeners = function (type) {
+ if (this._events[type]) {
+ delete this._events[type];
+ }
+ };
+ EventEmitter.prototype.emit = function (type) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ if (!this._events[type]) {
+ return;
+ }
+ var obj = this._events[type];
+ for (var i = 0; i < obj.length; i++) {
+ obj[i].apply(this, args);
+ }
+ };
+ EventEmitter.prototype.listeners = function (type) {
+ return this._events[type] || [];
+ };
+ EventEmitter.prototype.dispose = function () {
+ _super.prototype.dispose.call(this);
+ this._events = {};
+ };
+ return EventEmitter;
+}(Lifecycle_1.Disposable));
+exports.EventEmitter = EventEmitter;
+
+},{"./common/Lifecycle":17}],8:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var EscapeSequences_1 = require("./common/data/EscapeSequences");
+var Charsets_1 = require("./core/data/Charsets");
+var Buffer_1 = require("./Buffer");
+var CharWidth_1 = require("./CharWidth");
+var EscapeSequenceParser_1 = require("./EscapeSequenceParser");
+var Lifecycle_1 = require("./common/Lifecycle");
+var GLEVEL = { '(': 0, ')': 1, '*': 2, '+': 3, '-': 1, '.': 2 };
+var RequestTerminfo = (function () {
+ function RequestTerminfo(_terminal) {
+ this._terminal = _terminal;
+ }
+ RequestTerminfo.prototype.hook = function (collect, params, flag) {
+ this._data = '';
+ };
+ RequestTerminfo.prototype.put = function (data, start, end) {
+ this._data += data.substring(start, end);
+ };
+ RequestTerminfo.prototype.unhook = function () {
+ this._terminal.send(EscapeSequences_1.C0.ESC + "P0+r" + this._data + EscapeSequences_1.C0.ESC + "\\");
+ };
+ return RequestTerminfo;
+}());
+var DECRQSS = (function () {
+ function DECRQSS(_terminal) {
+ this._terminal = _terminal;
+ }
+ DECRQSS.prototype.hook = function (collect, params, flag) {
+ this._data = '';
+ };
+ DECRQSS.prototype.put = function (data, start, end) {
+ this._data += data.substring(start, end);
+ };
+ DECRQSS.prototype.unhook = function () {
+ switch (this._data) {
+ case '"q':
+ return this._terminal.send(EscapeSequences_1.C0.ESC + "P1$r0\"q" + EscapeSequences_1.C0.ESC + "\\");
+ case '"p':
+ return this._terminal.send(EscapeSequences_1.C0.ESC + "P1$r61\"p" + EscapeSequences_1.C0.ESC + "\\");
+ case 'r':
+ var pt = '' + (this._terminal.buffer.scrollTop + 1) +
+ ';' + (this._terminal.buffer.scrollBottom + 1) + 'r';
+ return this._terminal.send(EscapeSequences_1.C0.ESC + "P1$r" + pt + EscapeSequences_1.C0.ESC + "\\");
+ case 'm':
+ return this._terminal.send(EscapeSequences_1.C0.ESC + "P1$r0m" + EscapeSequences_1.C0.ESC + "\\");
+ case ' q':
+ var STYLES = { 'block': 2, 'underline': 4, 'bar': 6 };
+ var style = STYLES[this._terminal.getOption('cursorStyle')];
+ style -= this._terminal.getOption('cursorBlink');
+ return this._terminal.send(EscapeSequences_1.C0.ESC + "P1$r" + style + " q" + EscapeSequences_1.C0.ESC + "\\");
+ default:
+ this._terminal.error('Unknown DCS $q %s', this._data);
+ this._terminal.send(EscapeSequences_1.C0.ESC + "P0$r" + this._data + EscapeSequences_1.C0.ESC + "\\");
+ }
+ };
+ return DECRQSS;
+}());
+var InputHandler = (function (_super) {
+ __extends(InputHandler, _super);
+ function InputHandler(_terminal, _parser) {
+ if (_parser === void 0) { _parser = new EscapeSequenceParser_1.EscapeSequenceParser(); }
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._parser = _parser;
+ _this.register(_this._parser);
+ _this._surrogateHigh = '';
+ _this._parser.setCsiHandlerFallback(function (collect, params, flag) {
+ _this._terminal.error('Unknown CSI code: ', collect, params, String.fromCharCode(flag));
+ });
+ _this._parser.setEscHandlerFallback(function (collect, flag) {
+ _this._terminal.error('Unknown ESC code: ', collect, String.fromCharCode(flag));
+ });
+ _this._parser.setExecuteHandlerFallback(function (code) {
+ _this._terminal.error('Unknown EXECUTE code: ', code);
+ });
+ _this._parser.setOscHandlerFallback(function (identifier, data) {
+ _this._terminal.error('Unknown OSC code: ', identifier, data);
+ });
+ _this._parser.setPrintHandler(function (data, start, end) { return _this.print(data, start, end); });
+ _this._parser.setCsiHandler('@', function (params, collect) { return _this.insertChars(params); });
+ _this._parser.setCsiHandler('A', function (params, collect) { return _this.cursorUp(params); });
+ _this._parser.setCsiHandler('B', function (params, collect) { return _this.cursorDown(params); });
+ _this._parser.setCsiHandler('C', function (params, collect) { return _this.cursorForward(params); });
+ _this._parser.setCsiHandler('D', function (params, collect) { return _this.cursorBackward(params); });
+ _this._parser.setCsiHandler('E', function (params, collect) { return _this.cursorNextLine(params); });
+ _this._parser.setCsiHandler('F', function (params, collect) { return _this.cursorPrecedingLine(params); });
+ _this._parser.setCsiHandler('G', function (params, collect) { return _this.cursorCharAbsolute(params); });
+ _this._parser.setCsiHandler('H', function (params, collect) { return _this.cursorPosition(params); });
+ _this._parser.setCsiHandler('I', function (params, collect) { return _this.cursorForwardTab(params); });
+ _this._parser.setCsiHandler('J', function (params, collect) { return _this.eraseInDisplay(params); });
+ _this._parser.setCsiHandler('K', function (params, collect) { return _this.eraseInLine(params); });
+ _this._parser.setCsiHandler('L', function (params, collect) { return _this.insertLines(params); });
+ _this._parser.setCsiHandler('M', function (params, collect) { return _this.deleteLines(params); });
+ _this._parser.setCsiHandler('P', function (params, collect) { return _this.deleteChars(params); });
+ _this._parser.setCsiHandler('S', function (params, collect) { return _this.scrollUp(params); });
+ _this._parser.setCsiHandler('T', function (params, collect) { return _this.scrollDown(params, collect); });
+ _this._parser.setCsiHandler('X', function (params, collect) { return _this.eraseChars(params); });
+ _this._parser.setCsiHandler('Z', function (params, collect) { return _this.cursorBackwardTab(params); });
+ _this._parser.setCsiHandler('`', function (params, collect) { return _this.charPosAbsolute(params); });
+ _this._parser.setCsiHandler('a', function (params, collect) { return _this.hPositionRelative(params); });
+ _this._parser.setCsiHandler('b', function (params, collect) { return _this.repeatPrecedingCharacter(params); });
+ _this._parser.setCsiHandler('c', function (params, collect) { return _this.sendDeviceAttributes(params, collect); });
+ _this._parser.setCsiHandler('d', function (params, collect) { return _this.linePosAbsolute(params); });
+ _this._parser.setCsiHandler('e', function (params, collect) { return _this.vPositionRelative(params); });
+ _this._parser.setCsiHandler('f', function (params, collect) { return _this.hVPosition(params); });
+ _this._parser.setCsiHandler('g', function (params, collect) { return _this.tabClear(params); });
+ _this._parser.setCsiHandler('h', function (params, collect) { return _this.setMode(params, collect); });
+ _this._parser.setCsiHandler('l', function (params, collect) { return _this.resetMode(params, collect); });
+ _this._parser.setCsiHandler('m', function (params, collect) { return _this.charAttributes(params); });
+ _this._parser.setCsiHandler('n', function (params, collect) { return _this.deviceStatus(params, collect); });
+ _this._parser.setCsiHandler('p', function (params, collect) { return _this.softReset(params, collect); });
+ _this._parser.setCsiHandler('q', function (params, collect) { return _this.setCursorStyle(params, collect); });
+ _this._parser.setCsiHandler('r', function (params, collect) { return _this.setScrollRegion(params, collect); });
+ _this._parser.setCsiHandler('s', function (params, collect) { return _this.saveCursor(params); });
+ _this._parser.setCsiHandler('u', function (params, collect) { return _this.restoreCursor(params); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.BEL, function () { return _this.bell(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.LF, function () { return _this.lineFeed(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.VT, function () { return _this.lineFeed(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.FF, function () { return _this.lineFeed(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.CR, function () { return _this.carriageReturn(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.BS, function () { return _this.backspace(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.HT, function () { return _this.tab(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.SO, function () { return _this.shiftOut(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C0.SI, function () { return _this.shiftIn(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C1.IND, function () { return _this.index(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C1.NEL, function () { return _this.nextLine(); });
+ _this._parser.setExecuteHandler(EscapeSequences_1.C1.HTS, function () { return _this.tabSet(); });
+ _this._parser.setOscHandler(0, function (data) { return _this.setTitle(data); });
+ _this._parser.setOscHandler(2, function (data) { return _this.setTitle(data); });
+ _this._parser.setEscHandler('7', function () { return _this.saveCursor([]); });
+ _this._parser.setEscHandler('8', function () { return _this.restoreCursor([]); });
+ _this._parser.setEscHandler('D', function () { return _this.index(); });
+ _this._parser.setEscHandler('E', function () { return _this.nextLine(); });
+ _this._parser.setEscHandler('H', function () { return _this.tabSet(); });
+ _this._parser.setEscHandler('M', function () { return _this.reverseIndex(); });
+ _this._parser.setEscHandler('=', function () { return _this.keypadApplicationMode(); });
+ _this._parser.setEscHandler('>', function () { return _this.keypadNumericMode(); });
+ _this._parser.setEscHandler('c', function () { return _this.reset(); });
+ _this._parser.setEscHandler('n', function () { return _this.setgLevel(2); });
+ _this._parser.setEscHandler('o', function () { return _this.setgLevel(3); });
+ _this._parser.setEscHandler('|', function () { return _this.setgLevel(3); });
+ _this._parser.setEscHandler('}', function () { return _this.setgLevel(2); });
+ _this._parser.setEscHandler('~', function () { return _this.setgLevel(1); });
+ _this._parser.setEscHandler('%@', function () { return _this.selectDefaultCharset(); });
+ _this._parser.setEscHandler('%G', function () { return _this.selectDefaultCharset(); });
+ var _loop_1 = function (flag) {
+ this_1._parser.setEscHandler('(' + flag, function () { return _this.selectCharset('(' + flag); });
+ this_1._parser.setEscHandler(')' + flag, function () { return _this.selectCharset(')' + flag); });
+ this_1._parser.setEscHandler('*' + flag, function () { return _this.selectCharset('*' + flag); });
+ this_1._parser.setEscHandler('+' + flag, function () { return _this.selectCharset('+' + flag); });
+ this_1._parser.setEscHandler('-' + flag, function () { return _this.selectCharset('-' + flag); });
+ this_1._parser.setEscHandler('.' + flag, function () { return _this.selectCharset('.' + flag); });
+ this_1._parser.setEscHandler('/' + flag, function () { return _this.selectCharset('/' + flag); });
+ };
+ var this_1 = this;
+ for (var flag in Charsets_1.CHARSETS) {
+ _loop_1(flag);
+ }
+ _this._parser.setErrorHandler(function (state) {
+ _this._terminal.error('Parsing error: ', state);
+ return state;
+ });
+ _this._parser.setDcsHandler('$q', new DECRQSS(_this._terminal));
+ _this._parser.setDcsHandler('+q', new RequestTerminfo(_this._terminal));
+ return _this;
+ }
+ InputHandler.prototype.dispose = function () {
+ _super.prototype.dispose.call(this);
+ this._terminal = null;
+ };
+ InputHandler.prototype.parse = function (data) {
+ var buffer = this._terminal.buffer;
+ var cursorStartX = buffer.x;
+ var cursorStartY = buffer.y;
+ if (this._terminal.debug) {
+ this._terminal.log('data: ' + data);
+ }
+ if (this._surrogateHigh) {
+ data = this._surrogateHigh + data;
+ this._surrogateHigh = '';
+ }
+ this._parser.parse(data);
+ buffer = this._terminal.buffer;
+ if (buffer.x !== cursorStartX || buffer.y !== cursorStartY) {
+ this._terminal.emit('cursormove');
+ }
+ };
+ InputHandler.prototype.print = function (data, start, end) {
+ var char;
+ var code;
+ var low;
+ var chWidth;
+ var buffer = this._terminal.buffer;
+ var charset = this._terminal.charset;
+ var screenReaderMode = this._terminal.options.screenReaderMode;
+ var cols = this._terminal.cols;
+ var wraparoundMode = this._terminal.wraparoundMode;
+ var insertMode = this._terminal.insertMode;
+ var curAttr = this._terminal.curAttr;
+ var bufferRow = buffer.lines.get(buffer.y + buffer.ybase);
+ this._terminal.updateRange(buffer.y);
+ for (var stringPosition = start; stringPosition < end; ++stringPosition) {
+ char = data.charAt(stringPosition);
+ code = data.charCodeAt(stringPosition);
+ if (0xD800 <= code && code <= 0xDBFF) {
+ low = data.charCodeAt(stringPosition + 1);
+ if (isNaN(low)) {
+ this._surrogateHigh = char;
+ continue;
+ }
+ code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
+ char += data.charAt(stringPosition + 1);
+ }
+ if (0xDC00 <= code && code <= 0xDFFF) {
+ continue;
+ }
+ chWidth = CharWidth_1.wcwidth(code);
+ if (charset) {
+ char = charset[char] || char;
+ code = char.charCodeAt(0);
+ }
+ if (screenReaderMode) {
+ this._terminal.emit('a11y.char', char);
+ }
+ if (!chWidth && buffer.x) {
+ if (bufferRow[buffer.x - 1]) {
+ if (!bufferRow[buffer.x - 1][Buffer_1.CHAR_DATA_WIDTH_INDEX]) {
+ if (bufferRow[buffer.x - 2]) {
+ bufferRow[buffer.x - 2][Buffer_1.CHAR_DATA_CHAR_INDEX] += char;
+ bufferRow[buffer.x - 2][Buffer_1.CHAR_DATA_CODE_INDEX] = code;
+ }
+ }
+ else {
+ bufferRow[buffer.x - 1][Buffer_1.CHAR_DATA_CHAR_INDEX] += char;
+ bufferRow[buffer.x - 1][Buffer_1.CHAR_DATA_CODE_INDEX] = code;
+ }
+ }
+ continue;
+ }
+ if (buffer.x + chWidth - 1 >= cols) {
+ if (wraparoundMode) {
+ buffer.x = 0;
+ buffer.y++;
+ if (buffer.y > buffer.scrollBottom) {
+ buffer.y--;
+ this._terminal.scroll(true);
+ }
+ else {
+ buffer.lines.get(buffer.y).isWrapped = true;
+ }
+ bufferRow = buffer.lines.get(buffer.y + buffer.ybase);
+ }
+ else {
+ if (chWidth === 2) {
+ continue;
+ }
+ }
+ }
+ if (insertMode) {
+ for (var moves = 0; moves < chWidth; ++moves) {
+ var removed = bufferRow.pop();
+ if (removed[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0
+ && bufferRow[this._terminal.cols - 2]
+ && bufferRow[this._terminal.cols - 2][Buffer_1.CHAR_DATA_WIDTH_INDEX] === 2) {
+ bufferRow[this._terminal.cols - 2] = [curAttr, ' ', 1, 32];
+ }
+ bufferRow.splice(buffer.x, 0, [curAttr, ' ', 1, 32]);
+ }
+ }
+ bufferRow[buffer.x++] = [curAttr, char, chWidth, code];
+ if (chWidth === 2) {
+ bufferRow[buffer.x++] = [curAttr, '', 0, undefined];
+ }
+ }
+ this._terminal.updateRange(buffer.y);
+ };
+ InputHandler.prototype.bell = function () {
+ this._terminal.bell();
+ };
+ InputHandler.prototype.lineFeed = function () {
+ var buffer = this._terminal.buffer;
+ if (this._terminal.convertEol) {
+ buffer.x = 0;
+ }
+ buffer.y++;
+ if (buffer.y > buffer.scrollBottom) {
+ buffer.y--;
+ this._terminal.scroll();
+ }
+ if (buffer.x >= this._terminal.cols) {
+ buffer.x--;
+ }
+ this._terminal.emit('linefeed');
+ };
+ InputHandler.prototype.carriageReturn = function () {
+ this._terminal.buffer.x = 0;
+ };
+ InputHandler.prototype.backspace = function () {
+ if (this._terminal.buffer.x > 0) {
+ this._terminal.buffer.x--;
+ }
+ };
+ InputHandler.prototype.tab = function () {
+ var originalX = this._terminal.buffer.x;
+ this._terminal.buffer.x = this._terminal.buffer.nextStop();
+ if (this._terminal.options.screenReaderMode) {
+ this._terminal.emit('a11y.tab', this._terminal.buffer.x - originalX);
+ }
+ };
+ InputHandler.prototype.shiftOut = function () {
+ this._terminal.setgLevel(1);
+ };
+ InputHandler.prototype.shiftIn = function () {
+ this._terminal.setgLevel(0);
+ };
+ InputHandler.prototype.insertChars = function (params) {
+ var param = params[0];
+ if (param < 1)
+ param = 1;
+ var buffer = this._terminal.buffer;
+ var row = buffer.y + buffer.ybase;
+ var j = buffer.x;
+ var ch = [this._terminal.eraseAttr(), ' ', 1, 32];
+ while (param-- && j < this._terminal.cols) {
+ buffer.lines.get(row).splice(j++, 0, ch);
+ buffer.lines.get(row).pop();
+ }
+ };
+ InputHandler.prototype.cursorUp = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.y -= param;
+ if (this._terminal.buffer.y < 0) {
+ this._terminal.buffer.y = 0;
+ }
+ };
+ InputHandler.prototype.cursorDown = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.y += param;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
+ }
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
+ }
+ };
+ InputHandler.prototype.cursorForward = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.x += param;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
+ }
+ };
+ InputHandler.prototype.cursorBackward = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
+ }
+ this._terminal.buffer.x -= param;
+ if (this._terminal.buffer.x < 0) {
+ this._terminal.buffer.x = 0;
+ }
+ };
+ InputHandler.prototype.cursorNextLine = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.y += param;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
+ }
+ this._terminal.buffer.x = 0;
+ };
+ InputHandler.prototype.cursorPrecedingLine = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.y -= param;
+ if (this._terminal.buffer.y < 0) {
+ this._terminal.buffer.y = 0;
+ }
+ this._terminal.buffer.x = 0;
+ };
+ InputHandler.prototype.cursorCharAbsolute = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.x = param - 1;
+ };
+ InputHandler.prototype.cursorPosition = function (params) {
+ var col;
+ var row = params[0] - 1;
+ if (params.length >= 2) {
+ col = params[1] - 1;
+ }
+ else {
+ col = 0;
+ }
+ if (row < 0) {
+ row = 0;
+ }
+ else if (row >= this._terminal.rows) {
+ row = this._terminal.rows - 1;
+ }
+ if (col < 0) {
+ col = 0;
+ }
+ else if (col >= this._terminal.cols) {
+ col = this._terminal.cols - 1;
+ }
+ this._terminal.buffer.x = col;
+ this._terminal.buffer.y = row;
+ };
+ InputHandler.prototype.cursorForwardTab = function (params) {
+ var param = params[0] || 1;
+ while (param--) {
+ this._terminal.buffer.x = this._terminal.buffer.nextStop();
+ }
+ };
+ InputHandler.prototype.eraseInDisplay = function (params) {
+ var j;
+ switch (params[0]) {
+ case 0:
+ this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y);
+ j = this._terminal.buffer.y + 1;
+ for (; j < this._terminal.rows; j++) {
+ this._terminal.eraseLine(j);
+ }
+ break;
+ case 1:
+ this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y);
+ j = this._terminal.buffer.y;
+ while (j--) {
+ this._terminal.eraseLine(j);
+ }
+ break;
+ case 2:
+ j = this._terminal.rows;
+ while (j--)
+ this._terminal.eraseLine(j);
+ break;
+ case 3:
+ var scrollBackSize = this._terminal.buffer.lines.length - this._terminal.rows;
+ if (scrollBackSize > 0) {
+ this._terminal.buffer.lines.trimStart(scrollBackSize);
+ this._terminal.buffer.ybase = Math.max(this._terminal.buffer.ybase - scrollBackSize, 0);
+ this._terminal.buffer.ydisp = Math.max(this._terminal.buffer.ydisp - scrollBackSize, 0);
+ this._terminal.emit('scroll', 0);
+ }
+ break;
+ }
+ };
+ InputHandler.prototype.eraseInLine = function (params) {
+ switch (params[0]) {
+ case 0:
+ this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y);
+ break;
+ case 1:
+ this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y);
+ break;
+ case 2:
+ this._terminal.eraseLine(this._terminal.buffer.y);
+ break;
+ }
+ };
+ InputHandler.prototype.insertLines = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ var buffer = this._terminal.buffer;
+ var row = buffer.y + buffer.ybase;
+ var scrollBottomRowsOffset = this._terminal.rows - 1 - buffer.scrollBottom;
+ var scrollBottomAbsolute = this._terminal.rows - 1 + buffer.ybase - scrollBottomRowsOffset + 1;
+ while (param--) {
+ buffer.lines.splice(scrollBottomAbsolute - 1, 1);
+ buffer.lines.splice(row, 0, this._terminal.blankLine(true));
+ }
+ this._terminal.updateRange(buffer.y);
+ this._terminal.updateRange(buffer.scrollBottom);
+ };
+ InputHandler.prototype.deleteLines = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ var buffer = this._terminal.buffer;
+ var row = buffer.y + buffer.ybase;
+ var j;
+ j = this._terminal.rows - 1 - buffer.scrollBottom;
+ j = this._terminal.rows - 1 + buffer.ybase - j;
+ while (param--) {
+ buffer.lines.splice(row, 1);
+ buffer.lines.splice(j, 0, this._terminal.blankLine(true));
+ }
+ this._terminal.updateRange(buffer.y);
+ this._terminal.updateRange(buffer.scrollBottom);
+ };
+ InputHandler.prototype.deleteChars = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ var buffer = this._terminal.buffer;
+ var row = buffer.y + buffer.ybase;
+ var ch = [this._terminal.eraseAttr(), ' ', 1, 32];
+ while (param--) {
+ buffer.lines.get(row).splice(buffer.x, 1);
+ buffer.lines.get(row).push(ch);
+ }
+ this._terminal.updateRange(buffer.y);
+ };
+ InputHandler.prototype.scrollUp = function (params) {
+ var param = params[0] || 1;
+ var buffer = this._terminal.buffer;
+ while (param--) {
+ buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1);
+ buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, this._terminal.blankLine());
+ }
+ this._terminal.updateRange(buffer.scrollTop);
+ this._terminal.updateRange(buffer.scrollBottom);
+ };
+ InputHandler.prototype.scrollDown = function (params, collect) {
+ if (params.length < 2 && !collect) {
+ var param = params[0] || 1;
+ var buffer = this._terminal.buffer;
+ while (param--) {
+ buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1);
+ buffer.lines.splice(buffer.ybase + buffer.scrollTop, 0, this._terminal.blankLine());
+ }
+ this._terminal.updateRange(buffer.scrollTop);
+ this._terminal.updateRange(buffer.scrollBottom);
+ }
+ };
+ InputHandler.prototype.eraseChars = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ var buffer = this._terminal.buffer;
+ var row = buffer.y + buffer.ybase;
+ var j = buffer.x;
+ var ch = [this._terminal.eraseAttr(), ' ', 1, 32];
+ while (param-- && j < this._terminal.cols) {
+ buffer.lines.get(row)[j++] = ch;
+ }
+ };
+ InputHandler.prototype.cursorBackwardTab = function (params) {
+ var param = params[0] || 1;
+ var buffer = this._terminal.buffer;
+ while (param--) {
+ buffer.x = buffer.prevStop();
+ }
+ };
+ InputHandler.prototype.charPosAbsolute = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.x = param - 1;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
+ }
+ };
+ InputHandler.prototype.hPositionRelative = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.x += param;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
+ }
+ };
+ InputHandler.prototype.repeatPrecedingCharacter = function (params) {
+ var param = params[0] || 1;
+ var buffer = this._terminal.buffer;
+ var line = buffer.lines.get(buffer.ybase + buffer.y);
+ var ch = line[buffer.x - 1] || [Buffer_1.DEFAULT_ATTR, ' ', 1, 32];
+ while (param--) {
+ line[buffer.x++] = ch;
+ }
+ };
+ InputHandler.prototype.sendDeviceAttributes = function (params, collect) {
+ if (params[0] > 0) {
+ return;
+ }
+ if (!collect) {
+ if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) {
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[?1;2c');
+ }
+ else if (this._terminal.is('linux')) {
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[?6c');
+ }
+ }
+ else if (collect === '>') {
+ if (this._terminal.is('xterm')) {
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[>0;276;0c');
+ }
+ else if (this._terminal.is('rxvt-unicode')) {
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[>85;95;0c');
+ }
+ else if (this._terminal.is('linux')) {
+ this._terminal.send(params[0] + 'c');
+ }
+ else if (this._terminal.is('screen')) {
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[>83;40003;0c');
+ }
+ }
+ };
+ InputHandler.prototype.linePosAbsolute = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.y = param - 1;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
+ }
+ };
+ InputHandler.prototype.vPositionRelative = function (params) {
+ var param = params[0];
+ if (param < 1) {
+ param = 1;
+ }
+ this._terminal.buffer.y += param;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
+ }
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
+ }
+ };
+ InputHandler.prototype.hVPosition = function (params) {
+ if (params[0] < 1)
+ params[0] = 1;
+ if (params[1] < 1)
+ params[1] = 1;
+ this._terminal.buffer.y = params[0] - 1;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
+ }
+ this._terminal.buffer.x = params[1] - 1;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
+ }
+ };
+ InputHandler.prototype.tabClear = function (params) {
+ var param = params[0];
+ if (param <= 0) {
+ delete this._terminal.buffer.tabs[this._terminal.buffer.x];
+ }
+ else if (param === 3) {
+ this._terminal.buffer.tabs = {};
+ }
+ };
+ InputHandler.prototype.setMode = function (params, collect) {
+ if (params.length > 1) {
+ for (var i = 0; i < params.length; i++) {
+ this.setMode([params[i]]);
+ }
+ return;
+ }
+ if (!collect) {
+ switch (params[0]) {
+ case 4:
+ this._terminal.insertMode = true;
+ break;
+ case 20:
+ break;
+ }
+ }
+ else if (collect === '?') {
+ switch (params[0]) {
+ case 1:
+ this._terminal.applicationCursor = true;
+ break;
+ case 2:
+ this._terminal.setgCharset(0, Charsets_1.DEFAULT_CHARSET);
+ this._terminal.setgCharset(1, Charsets_1.DEFAULT_CHARSET);
+ this._terminal.setgCharset(2, Charsets_1.DEFAULT_CHARSET);
+ this._terminal.setgCharset(3, Charsets_1.DEFAULT_CHARSET);
+ break;
+ case 3:
+ this._terminal.savedCols = this._terminal.cols;
+ this._terminal.resize(132, this._terminal.rows);
+ break;
+ case 6:
+ this._terminal.originMode = true;
+ break;
+ case 7:
+ this._terminal.wraparoundMode = true;
+ break;
+ case 12:
+ break;
+ case 66:
+ this._terminal.log('Serial port requested application keypad.');
+ this._terminal.applicationKeypad = true;
+ this._terminal.viewport.syncScrollArea();
+ break;
+ case 9:
+ case 1000:
+ case 1002:
+ case 1003:
+ this._terminal.x10Mouse = params[0] === 9;
+ this._terminal.vt200Mouse = params[0] === 1000;
+ this._terminal.normalMouse = params[0] > 1000;
+ this._terminal.mouseEvents = true;
+ this._terminal.element.classList.add('enable-mouse-events');
+ this._terminal.selectionManager.disable();
+ this._terminal.log('Binding to mouse events.');
+ break;
+ case 1004:
+ this._terminal.sendFocus = true;
+ break;
+ case 1005:
+ this._terminal.utfMouse = true;
+ break;
+ case 1006:
+ this._terminal.sgrMouse = true;
+ break;
+ case 1015:
+ this._terminal.urxvtMouse = true;
+ break;
+ case 25:
+ this._terminal.cursorHidden = false;
+ break;
+ case 1049:
+ case 47:
+ case 1047:
+ this._terminal.buffers.activateAltBuffer();
+ this._terminal.viewport.syncScrollArea();
+ this._terminal.showCursor();
+ break;
+ case 2004:
+ this._terminal.bracketedPasteMode = true;
+ break;
+ }
+ }
+ };
+ InputHandler.prototype.resetMode = function (params, collect) {
+ if (params.length > 1) {
+ for (var i = 0; i < params.length; i++) {
+ this.resetMode([params[i]]);
+ }
+ return;
+ }
+ if (!collect) {
+ switch (params[0]) {
+ case 4:
+ this._terminal.insertMode = false;
+ break;
+ case 20:
+ break;
+ }
+ }
+ else if (collect === '?') {
+ switch (params[0]) {
+ case 1:
+ this._terminal.applicationCursor = false;
+ break;
+ case 3:
+ if (this._terminal.cols === 132 && this._terminal.savedCols) {
+ this._terminal.resize(this._terminal.savedCols, this._terminal.rows);
+ }
+ delete this._terminal.savedCols;
+ break;
+ case 6:
+ this._terminal.originMode = false;
+ break;
+ case 7:
+ this._terminal.wraparoundMode = false;
+ break;
+ case 12:
+ break;
+ case 66:
+ this._terminal.log('Switching back to normal keypad.');
+ this._terminal.applicationKeypad = false;
+ this._terminal.viewport.syncScrollArea();
+ break;
+ case 9:
+ case 1000:
+ case 1002:
+ case 1003:
+ this._terminal.x10Mouse = false;
+ this._terminal.vt200Mouse = false;
+ this._terminal.normalMouse = false;
+ this._terminal.mouseEvents = false;
+ this._terminal.element.classList.remove('enable-mouse-events');
+ this._terminal.selectionManager.enable();
+ break;
+ case 1004:
+ this._terminal.sendFocus = false;
+ break;
+ case 1005:
+ this._terminal.utfMouse = false;
+ break;
+ case 1006:
+ this._terminal.sgrMouse = false;
+ break;
+ case 1015:
+ this._terminal.urxvtMouse = false;
+ break;
+ case 25:
+ this._terminal.cursorHidden = true;
+ break;
+ case 1049:
+ case 47:
+ case 1047:
+ this._terminal.buffers.activateNormalBuffer();
+ this._terminal.refresh(0, this._terminal.rows - 1);
+ this._terminal.viewport.syncScrollArea();
+ this._terminal.showCursor();
+ break;
+ case 2004:
+ this._terminal.bracketedPasteMode = false;
+ break;
+ }
+ }
+ };
+ InputHandler.prototype.charAttributes = function (params) {
+ if (params.length === 1 && params[0] === 0) {
+ this._terminal.curAttr = Buffer_1.DEFAULT_ATTR;
+ return;
+ }
+ var l = params.length;
+ var flags = this._terminal.curAttr >> 18;
+ var fg = (this._terminal.curAttr >> 9) & 0x1ff;
+ var bg = this._terminal.curAttr & 0x1ff;
+ var p;
+ for (var i = 0; i < l; i++) {
+ p = params[i];
+ if (p >= 30 && p <= 37) {
+ fg = p - 30;
+ }
+ else if (p >= 40 && p <= 47) {
+ bg = p - 40;
+ }
+ else if (p >= 90 && p <= 97) {
+ p += 8;
+ fg = p - 90;
+ }
+ else if (p >= 100 && p <= 107) {
+ p += 8;
+ bg = p - 100;
+ }
+ else if (p === 0) {
+ flags = Buffer_1.DEFAULT_ATTR >> 18;
+ fg = (Buffer_1.DEFAULT_ATTR >> 9) & 0x1ff;
+ bg = Buffer_1.DEFAULT_ATTR & 0x1ff;
+ }
+ else if (p === 1) {
+ flags |= 1;
+ }
+ else if (p === 3) {
+ flags |= 64;
+ }
+ else if (p === 4) {
+ flags |= 2;
+ }
+ else if (p === 5) {
+ flags |= 4;
+ }
+ else if (p === 7) {
+ flags |= 8;
+ }
+ else if (p === 8) {
+ flags |= 16;
+ }
+ else if (p === 2) {
+ flags |= 32;
+ }
+ else if (p === 22) {
+ flags &= ~1;
+ flags &= ~32;
+ }
+ else if (p === 24) {
+ flags &= ~2;
+ }
+ else if (p === 25) {
+ flags &= ~4;
+ }
+ else if (p === 27) {
+ flags &= ~8;
+ }
+ else if (p === 28) {
+ flags &= ~16;
+ }
+ else if (p === 39) {
+ fg = (Buffer_1.DEFAULT_ATTR >> 9) & 0x1ff;
+ }
+ else if (p === 49) {
+ bg = Buffer_1.DEFAULT_ATTR & 0x1ff;
+ }
+ else if (p === 38) {
+ if (params[i + 1] === 2) {
+ i += 2;
+ fg = this._terminal.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;
+ p = params[i] & 0xff;
+ fg = p;
+ }
+ }
+ else if (p === 48) {
+ if (params[i + 1] === 2) {
+ i += 2;
+ bg = this._terminal.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;
+ p = params[i] & 0xff;
+ bg = p;
+ }
+ }
+ else if (p === 100) {
+ fg = (Buffer_1.DEFAULT_ATTR >> 9) & 0x1ff;
+ bg = Buffer_1.DEFAULT_ATTR & 0x1ff;
+ }
+ else {
+ this._terminal.error('Unknown SGR attribute: %d.', p);
+ }
+ }
+ this._terminal.curAttr = (flags << 18) | (fg << 9) | bg;
+ };
+ InputHandler.prototype.deviceStatus = function (params, collect) {
+ if (!collect) {
+ switch (params[0]) {
+ case 5:
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[0n');
+ break;
+ case 6:
+ this._terminal.send(EscapeSequences_1.C0.ESC + '['
+ + (this._terminal.buffer.y + 1)
+ + ';'
+ + (this._terminal.buffer.x + 1)
+ + 'R');
+ break;
+ }
+ }
+ else if (collect === '?') {
+ switch (params[0]) {
+ case 6:
+ this._terminal.send(EscapeSequences_1.C0.ESC + '[?'
+ + (this._terminal.buffer.y + 1)
+ + ';'
+ + (this._terminal.buffer.x + 1)
+ + 'R');
+ break;
+ case 15:
+ break;
+ case 25:
+ break;
+ case 26:
+ break;
+ case 53:
+ break;
+ }
+ }
+ };
+ InputHandler.prototype.softReset = function (params, collect) {
+ if (collect === '!') {
+ this._terminal.cursorHidden = false;
+ this._terminal.insertMode = false;
+ this._terminal.originMode = false;
+ this._terminal.wraparoundMode = true;
+ this._terminal.applicationKeypad = false;
+ this._terminal.viewport.syncScrollArea();
+ this._terminal.applicationCursor = false;
+ this._terminal.buffer.scrollTop = 0;
+ this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
+ this._terminal.curAttr = Buffer_1.DEFAULT_ATTR;
+ this._terminal.buffer.x = this._terminal.buffer.y = 0;
+ this._terminal.charset = null;
+ this._terminal.glevel = 0;
+ this._terminal.charsets = [null];
+ }
+ };
+ InputHandler.prototype.setCursorStyle = function (params, collect) {
+ if (collect === ' ') {
+ var param = params[0] < 1 ? 1 : params[0];
+ switch (param) {
+ case 1:
+ case 2:
+ this._terminal.setOption('cursorStyle', 'block');
+ break;
+ case 3:
+ case 4:
+ this._terminal.setOption('cursorStyle', 'underline');
+ break;
+ case 5:
+ case 6:
+ this._terminal.setOption('cursorStyle', 'bar');
+ break;
+ }
+ var isBlinking = param % 2 === 1;
+ this._terminal.setOption('cursorBlink', isBlinking);
+ }
+ };
+ InputHandler.prototype.setScrollRegion = function (params, collect) {
+ if (collect)
+ return;
+ this._terminal.buffer.scrollTop = (params[0] || 1) - 1;
+ this._terminal.buffer.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1;
+ this._terminal.buffer.x = 0;
+ this._terminal.buffer.y = 0;
+ };
+ InputHandler.prototype.saveCursor = function (params) {
+ this._terminal.buffer.savedX = this._terminal.buffer.x;
+ this._terminal.buffer.savedY = this._terminal.buffer.y;
+ this._terminal.savedCurAttr = this._terminal.curAttr;
+ };
+ InputHandler.prototype.restoreCursor = function (params) {
+ this._terminal.buffer.x = this._terminal.buffer.savedX || 0;
+ this._terminal.buffer.y = this._terminal.buffer.savedY || 0;
+ this._terminal.curAttr = this._terminal.savedCurAttr || Buffer_1.DEFAULT_ATTR;
+ };
+ InputHandler.prototype.setTitle = function (data) {
+ this._terminal.handleTitle(data);
+ };
+ InputHandler.prototype.nextLine = function () {
+ this._terminal.buffer.x = 0;
+ this.index();
+ };
+ InputHandler.prototype.keypadApplicationMode = function () {
+ this._terminal.log('Serial port requested application keypad.');
+ this._terminal.applicationKeypad = true;
+ if (this._terminal.viewport) {
+ this._terminal.viewport.syncScrollArea();
+ }
+ };
+ InputHandler.prototype.keypadNumericMode = function () {
+ this._terminal.log('Switching back to normal keypad.');
+ this._terminal.applicationKeypad = false;
+ if (this._terminal.viewport) {
+ this._terminal.viewport.syncScrollArea();
+ }
+ };
+ InputHandler.prototype.selectDefaultCharset = function () {
+ this._terminal.setgLevel(0);
+ this._terminal.setgCharset(0, Charsets_1.DEFAULT_CHARSET);
+ };
+ InputHandler.prototype.selectCharset = function (collectAndFlag) {
+ if (collectAndFlag.length !== 2)
+ return this.selectDefaultCharset();
+ if (collectAndFlag[0] === '/')
+ return;
+ this._terminal.setgCharset(GLEVEL[collectAndFlag[0]], Charsets_1.CHARSETS[collectAndFlag[1]] || Charsets_1.DEFAULT_CHARSET);
+ };
+ InputHandler.prototype.index = function () {
+ this._terminal.index();
+ };
+ InputHandler.prototype.tabSet = function () {
+ this._terminal.tabSet();
+ };
+ InputHandler.prototype.reverseIndex = function () {
+ this._terminal.reverseIndex();
+ };
+ InputHandler.prototype.reset = function () {
+ this._parser.reset();
+ this._terminal.reset();
+ };
+ InputHandler.prototype.setgLevel = function (level) {
+ this._terminal.setgLevel(level);
+ };
+ return InputHandler;
+}(Lifecycle_1.Disposable));
+exports.InputHandler = InputHandler;
+
+},{"./Buffer":2,"./CharWidth":4,"./EscapeSequenceParser":6,"./common/Lifecycle":17,"./common/data/EscapeSequences":18,"./core/data/Charsets":19}],9:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var MouseZoneManager_1 = require("./ui/MouseZoneManager");
+var EventEmitter_1 = require("./EventEmitter");
+var Linkifier = (function (_super) {
+ __extends(Linkifier, _super);
+ function Linkifier(_terminal) {
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._linkMatchers = [];
+ _this._nextLinkMatcherId = 0;
+ _this._rowsToLinkify = {
+ start: null,
+ end: null
+ };
+ return _this;
+ }
+ Linkifier.prototype.attachToDom = function (mouseZoneManager) {
+ this._mouseZoneManager = mouseZoneManager;
+ };
+ Linkifier.prototype.linkifyRows = function (start, end) {
+ var _this = this;
+ if (!this._mouseZoneManager) {
+ return;
+ }
+ if (this._rowsToLinkify.start === null) {
+ this._rowsToLinkify.start = start;
+ this._rowsToLinkify.end = end;
+ }
+ else {
+ this._rowsToLinkify.start = Math.min(this._rowsToLinkify.start, start);
+ this._rowsToLinkify.end = Math.max(this._rowsToLinkify.end, end);
+ }
+ this._mouseZoneManager.clearAll(start, end);
+ if (this._rowsTimeoutId) {
+ clearTimeout(this._rowsTimeoutId);
+ }
+ this._rowsTimeoutId = setTimeout(function () { return _this._linkifyRows(); }, Linkifier.TIME_BEFORE_LINKIFY);
+ };
+ Linkifier.prototype._linkifyRows = function () {
+ this._rowsTimeoutId = null;
+ for (var i = this._rowsToLinkify.start; i <= this._rowsToLinkify.end; i++) {
+ this._linkifyRow(i);
+ }
+ this._rowsToLinkify.start = null;
+ this._rowsToLinkify.end = null;
+ };
+ Linkifier.prototype.registerLinkMatcher = function (regex, handler, options) {
+ if (options === void 0) { options = {}; }
+ if (!handler) {
+ throw new Error('handler must be defined');
+ }
+ var matcher = {
+ id: this._nextLinkMatcherId++,
+ regex: regex,
+ handler: handler,
+ matchIndex: options.matchIndex,
+ validationCallback: options.validationCallback,
+ hoverTooltipCallback: options.tooltipCallback,
+ hoverLeaveCallback: options.leaveCallback,
+ willLinkActivate: options.willLinkActivate,
+ priority: options.priority || 0
+ };
+ this._addLinkMatcherToList(matcher);
+ return matcher.id;
+ };
+ Linkifier.prototype._addLinkMatcherToList = function (matcher) {
+ if (this._linkMatchers.length === 0) {
+ this._linkMatchers.push(matcher);
+ return;
+ }
+ for (var i = this._linkMatchers.length - 1; i >= 0; i--) {
+ if (matcher.priority <= this._linkMatchers[i].priority) {
+ this._linkMatchers.splice(i + 1, 0, matcher);
+ return;
+ }
+ }
+ this._linkMatchers.splice(0, 0, matcher);
+ };
+ Linkifier.prototype.deregisterLinkMatcher = function (matcherId) {
+ for (var i = 0; i < this._linkMatchers.length; i++) {
+ if (this._linkMatchers[i].id === matcherId) {
+ this._linkMatchers.splice(i, 1);
+ return true;
+ }
+ }
+ return false;
+ };
+ Linkifier.prototype._linkifyRow = function (rowIndex) {
+ var absoluteRowIndex = this._terminal.buffer.ydisp + rowIndex;
+ if (absoluteRowIndex >= this._terminal.buffer.lines.length) {
+ return;
+ }
+ if (this._terminal.buffer.lines.get(absoluteRowIndex).isWrapped) {
+ if (rowIndex !== 0) {
+ return;
+ }
+ do {
+ rowIndex--;
+ absoluteRowIndex--;
+ } while (this._terminal.buffer.lines.get(absoluteRowIndex).isWrapped);
+ }
+ var text = this._terminal.buffer.translateBufferLineToString(absoluteRowIndex, false);
+ var currentIndex = absoluteRowIndex + 1;
+ while (currentIndex < this._terminal.buffer.lines.length &&
+ this._terminal.buffer.lines.get(currentIndex).isWrapped) {
+ text += this._terminal.buffer.translateBufferLineToString(currentIndex++, false);
+ }
+ for (var i = 0; i < this._linkMatchers.length; i++) {
+ this._doLinkifyRow(rowIndex, text, this._linkMatchers[i]);
+ }
+ };
+ Linkifier.prototype._doLinkifyRow = function (rowIndex, text, matcher, offset) {
+ var _this = this;
+ if (offset === void 0) { offset = 0; }
+ var match = text.match(matcher.regex);
+ if (!match || match.length === 0) {
+ return;
+ }
+ var uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex];
+ var index = text.indexOf(uri);
+ if (matcher.validationCallback) {
+ matcher.validationCallback(uri, function (isValid) {
+ if (_this._rowsTimeoutId) {
+ return;
+ }
+ if (isValid) {
+ _this._addLink(offset + index, rowIndex, uri, matcher);
+ }
+ });
+ }
+ else {
+ this._addLink(offset + index, rowIndex, uri, matcher);
+ }
+ var remainingStartIndex = index + uri.length;
+ var remainingText = text.substr(remainingStartIndex);
+ if (remainingText.length > 0) {
+ this._doLinkifyRow(rowIndex, remainingText, matcher, offset + remainingStartIndex);
+ }
+ };
+ Linkifier.prototype._addLink = function (x, y, uri, matcher) {
+ var _this = this;
+ var x1 = x % this._terminal.cols;
+ var y1 = y + Math.floor(x / this._terminal.cols);
+ var x2 = (x1 + uri.length) % this._terminal.cols;
+ var y2 = y1 + Math.floor((x1 + uri.length) / this._terminal.cols);
+ if (x2 === 0) {
+ x2 = this._terminal.cols;
+ y2--;
+ }
+ this._mouseZoneManager.add(new MouseZoneManager_1.MouseZone(x1 + 1, y1 + 1, x2 + 1, y2 + 1, function (e) {
+ if (matcher.handler) {
+ return matcher.handler(e, uri);
+ }
+ window.open(uri, '_blank');
+ }, function (e) {
+ _this.emit("linkhover", _this._createLinkHoverEvent(x1, y1, x2, y2));
+ _this._terminal.element.classList.add('xterm-cursor-pointer');
+ }, function (e) {
+ _this.emit("linktooltip", _this._createLinkHoverEvent(x1, y1, x2, y2));
+ if (matcher.hoverTooltipCallback) {
+ matcher.hoverTooltipCallback(e, uri);
+ }
+ }, function () {
+ _this.emit("linkleave", _this._createLinkHoverEvent(x1, y1, x2, y2));
+ _this._terminal.element.classList.remove('xterm-cursor-pointer');
+ if (matcher.hoverLeaveCallback) {
+ matcher.hoverLeaveCallback();
+ }
+ }, function (e) {
+ if (matcher.willLinkActivate) {
+ return matcher.willLinkActivate(e, uri);
+ }
+ return true;
+ }));
+ };
+ Linkifier.prototype._createLinkHoverEvent = function (x1, y1, x2, y2) {
+ return { x1: x1, y1: y1, x2: x2, y2: y2, cols: this._terminal.cols };
+ };
+ Linkifier.TIME_BEFORE_LINKIFY = 200;
+ return Linkifier;
+}(EventEmitter_1.EventEmitter));
+exports.Linkifier = Linkifier;
+
+},{"./EventEmitter":7,"./ui/MouseZoneManager":47}],10:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var MouseHelper_1 = require("./utils/MouseHelper");
+var Browser = require("./shared/utils/Browser");
+var EventEmitter_1 = require("./EventEmitter");
+var SelectionModel_1 = require("./SelectionModel");
+var Buffer_1 = require("./Buffer");
+var AltClickHandler_1 = require("./handlers/AltClickHandler");
+var DRAG_SCROLL_MAX_THRESHOLD = 50;
+var DRAG_SCROLL_MAX_SPEED = 15;
+var DRAG_SCROLL_INTERVAL = 50;
+var ALT_CLICK_MOVE_CURSOR_TIME = 500;
+var WORD_SEPARATORS = ' ()[]{}\'"';
+var NON_BREAKING_SPACE_CHAR = String.fromCharCode(160);
+var ALL_NON_BREAKING_SPACE_REGEX = new RegExp(NON_BREAKING_SPACE_CHAR, 'g');
+var SelectionManager = (function (_super) {
+ __extends(SelectionManager, _super);
+ function SelectionManager(_terminal, _charMeasure) {
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._charMeasure = _charMeasure;
+ _this._enabled = true;
+ _this._initListeners();
+ _this.enable();
+ _this._model = new SelectionModel_1.SelectionModel(_terminal);
+ _this._activeSelectionMode = 0;
+ return _this;
+ }
+ SelectionManager.prototype.dispose = function () {
+ _super.prototype.dispose.call(this);
+ this._removeMouseDownListeners();
+ };
+ Object.defineProperty(SelectionManager.prototype, "_buffer", {
+ get: function () {
+ return this._terminal.buffers.active;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ SelectionManager.prototype._initListeners = function () {
+ var _this = this;
+ this._mouseMoveListener = function (event) { return _this._onMouseMove(event); };
+ this._mouseUpListener = function (event) { return _this._onMouseUp(event); };
+ this._trimListener = function (amount) { return _this._onTrim(amount); };
+ this.initBuffersListeners();
+ };
+ SelectionManager.prototype.initBuffersListeners = function () {
+ var _this = this;
+ this._terminal.buffer.lines.on('trim', this._trimListener);
+ this._terminal.buffers.on('activate', function (e) { return _this._onBufferActivate(e); });
+ };
+ SelectionManager.prototype.disable = function () {
+ this.clearSelection();
+ this._enabled = false;
+ };
+ SelectionManager.prototype.enable = function () {
+ this._enabled = true;
+ };
+ Object.defineProperty(SelectionManager.prototype, "selectionStart", {
+ get: function () { return this._model.finalSelectionStart; },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(SelectionManager.prototype, "selectionEnd", {
+ get: function () { return this._model.finalSelectionEnd; },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(SelectionManager.prototype, "hasSelection", {
+ get: function () {
+ var start = this._model.finalSelectionStart;
+ var end = this._model.finalSelectionEnd;
+ if (!start || !end) {
+ return false;
+ }
+ return start[0] !== end[0] || start[1] !== end[1];
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(SelectionManager.prototype, "selectionText", {
+ get: function () {
+ var start = this._model.finalSelectionStart;
+ var end = this._model.finalSelectionEnd;
+ if (!start || !end) {
+ return '';
+ }
+ var result = [];
+ if (this._activeSelectionMode === 3) {
+ if (start[0] === end[0]) {
+ return '';
+ }
+ for (var i = start[1]; i <= end[1]; i++) {
+ var lineText = this._buffer.translateBufferLineToString(i, true, start[0], end[0]);
+ result.push(lineText);
+ }
+ }
+ else {
+ var startRowEndCol = start[1] === end[1] ? end[0] : null;
+ result.push(this._buffer.translateBufferLineToString(start[1], true, start[0], startRowEndCol));
+ for (var i = start[1] + 1; i <= end[1] - 1; i++) {
+ var bufferLine = this._buffer.lines.get(i);
+ var lineText = this._buffer.translateBufferLineToString(i, true);
+ if (bufferLine.isWrapped) {
+ result[result.length - 1] += lineText;
+ }
+ else {
+ result.push(lineText);
+ }
+ }
+ if (start[1] !== end[1]) {
+ var bufferLine = this._buffer.lines.get(end[1]);
+ var lineText = this._buffer.translateBufferLineToString(end[1], true, 0, end[0]);
+ if (bufferLine.isWrapped) {
+ result[result.length - 1] += lineText;
+ }
+ else {
+ result.push(lineText);
+ }
+ }
+ }
+ var formattedResult = result.map(function (line) {
+ return line.replace(ALL_NON_BREAKING_SPACE_REGEX, ' ');
+ }).join(Browser.isMSWindows ? '\r\n' : '\n');
+ return formattedResult;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ SelectionManager.prototype.clearSelection = function () {
+ this._model.clearSelection();
+ this._removeMouseDownListeners();
+ this.refresh();
+ };
+ SelectionManager.prototype.refresh = function (isNewSelection) {
+ var _this = this;
+ if (!this._refreshAnimationFrame) {
+ this._refreshAnimationFrame = window.requestAnimationFrame(function () { return _this._refresh(); });
+ }
+ if (Browser.isLinux && isNewSelection) {
+ var selectionText = this.selectionText;
+ if (selectionText.length) {
+ this.emit('newselection', this.selectionText);
+ }
+ }
+ };
+ SelectionManager.prototype._refresh = function () {
+ this._refreshAnimationFrame = null;
+ this.emit('refresh', {
+ start: this._model.finalSelectionStart,
+ end: this._model.finalSelectionEnd,
+ columnSelectMode: this._activeSelectionMode === 3
+ });
+ };
+ SelectionManager.prototype.isClickInSelection = function (event) {
+ var coords = this._getMouseBufferCoords(event);
+ var start = this._model.finalSelectionStart;
+ var end = this._model.finalSelectionEnd;
+ if (!start || !end) {
+ return false;
+ }
+ return (coords[1] > start[1] && coords[1] < end[1]) ||
+ (start[1] === end[1] && coords[1] === start[1] && coords[0] > start[0] && coords[0] < end[0]) ||
+ (start[1] < end[1] && coords[1] === end[1] && coords[0] < end[0]);
+ };
+ SelectionManager.prototype.selectWordAtCursor = function (event) {
+ var coords = this._getMouseBufferCoords(event);
+ if (coords) {
+ this._selectWordAt(coords, false);
+ this._model.selectionEnd = null;
+ this.refresh(true);
+ }
+ };
+ SelectionManager.prototype.selectAll = function () {
+ this._model.isSelectAllActive = true;
+ this.refresh();
+ this._terminal.emit('selection');
+ };
+ SelectionManager.prototype.selectLines = function (start, end) {
+ this._model.clearSelection();
+ start = Math.max(start, 0);
+ end = Math.min(end, this._terminal.buffer.lines.length - 1);
+ this._model.selectionStart = [0, start];
+ this._model.selectionEnd = [this._terminal.cols, end];
+ this.refresh();
+ this._terminal.emit('selection');
+ };
+ SelectionManager.prototype._onTrim = function (amount) {
+ var needsRefresh = this._model.onTrim(amount);
+ if (needsRefresh) {
+ this.refresh();
+ }
+ };
+ SelectionManager.prototype._getMouseBufferCoords = function (event) {
+ var coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, true);
+ if (!coords) {
+ return null;
+ }
+ coords[0]--;
+ coords[1]--;
+ coords[1] += this._terminal.buffer.ydisp;
+ return coords;
+ };
+ SelectionManager.prototype._getMouseEventScrollAmount = function (event) {
+ var offset = MouseHelper_1.MouseHelper.getCoordsRelativeToElement(event, this._terminal.screenElement)[1];
+ var terminalHeight = this._terminal.rows * Math.ceil(this._charMeasure.height * this._terminal.options.lineHeight);
+ if (offset >= 0 && offset <= terminalHeight) {
+ return 0;
+ }
+ if (offset > terminalHeight) {
+ offset -= terminalHeight;
+ }
+ offset = Math.min(Math.max(offset, -DRAG_SCROLL_MAX_THRESHOLD), DRAG_SCROLL_MAX_THRESHOLD);
+ offset /= DRAG_SCROLL_MAX_THRESHOLD;
+ return (offset / Math.abs(offset)) + Math.round(offset * (DRAG_SCROLL_MAX_SPEED - 1));
+ };
+ SelectionManager.prototype.shouldForceSelection = function (event) {
+ if (Browser.isMac) {
+ return event.altKey && this._terminal.options.macOptionClickForcesSelection;
+ }
+ return event.shiftKey;
+ };
+ SelectionManager.prototype.onMouseDown = function (event) {
+ this._mouseDownTimeStamp = event.timeStamp;
+ if (event.button === 2 && this.hasSelection) {
+ return;
+ }
+ if (event.button !== 0) {
+ return;
+ }
+ if (!this._enabled) {
+ if (!this.shouldForceSelection(event)) {
+ return;
+ }
+ event.stopPropagation();
+ }
+ event.preventDefault();
+ this._dragScrollAmount = 0;
+ if (this._enabled && event.shiftKey) {
+ this._onIncrementalClick(event);
+ }
+ else {
+ if (event.detail === 1) {
+ this._onSingleClick(event);
+ }
+ else if (event.detail === 2) {
+ this._onDoubleClick(event);
+ }
+ else if (event.detail === 3) {
+ this._onTripleClick(event);
+ }
+ }
+ this._addMouseDownListeners();
+ this.refresh(true);
+ };
+ SelectionManager.prototype._addMouseDownListeners = function () {
+ var _this = this;
+ this._terminal.element.ownerDocument.addEventListener('mousemove', this._mouseMoveListener);
+ this._terminal.element.ownerDocument.addEventListener('mouseup', this._mouseUpListener);
+ this._dragScrollIntervalTimer = setInterval(function () { return _this._dragScroll(); }, DRAG_SCROLL_INTERVAL);
+ };
+ SelectionManager.prototype._removeMouseDownListeners = function () {
+ this._terminal.element.ownerDocument.removeEventListener('mousemove', this._mouseMoveListener);
+ this._terminal.element.ownerDocument.removeEventListener('mouseup', this._mouseUpListener);
+ clearInterval(this._dragScrollIntervalTimer);
+ this._dragScrollIntervalTimer = null;
+ };
+ SelectionManager.prototype._onIncrementalClick = function (event) {
+ if (this._model.selectionStart) {
+ this._model.selectionEnd = this._getMouseBufferCoords(event);
+ }
+ };
+ SelectionManager.prototype._onSingleClick = function (event) {
+ this._model.selectionStartLength = 0;
+ this._model.isSelectAllActive = false;
+ this._activeSelectionMode = this.shouldColumnSelect(event) ? 3 : 0;
+ this._model.selectionStart = this._getMouseBufferCoords(event);
+ if (!this._model.selectionStart) {
+ return;
+ }
+ this._model.selectionEnd = null;
+ var line = this._buffer.lines.get(this._model.selectionStart[1]);
+ if (!line) {
+ return;
+ }
+ if (line.length >= this._model.selectionStart[0]) {
+ return;
+ }
+ var char = line[this._model.selectionStart[0]];
+ if (char[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0) {
+ this._model.selectionStart[0]++;
+ }
+ };
+ SelectionManager.prototype._onDoubleClick = function (event) {
+ var coords = this._getMouseBufferCoords(event);
+ if (coords) {
+ this._activeSelectionMode = 1;
+ this._selectWordAt(coords, true);
+ }
+ };
+ SelectionManager.prototype._onTripleClick = function (event) {
+ var coords = this._getMouseBufferCoords(event);
+ if (coords) {
+ this._activeSelectionMode = 2;
+ this._selectLineAt(coords[1]);
+ }
+ };
+ SelectionManager.prototype.shouldColumnSelect = function (event) {
+ return event.altKey && !(Browser.isMac && this._terminal.options.macOptionClickForcesSelection);
+ };
+ SelectionManager.prototype._onMouseMove = function (event) {
+ event.stopImmediatePropagation();
+ var previousSelectionEnd = this._model.selectionEnd ? [this._model.selectionEnd[0], this._model.selectionEnd[1]] : null;
+ this._model.selectionEnd = this._getMouseBufferCoords(event);
+ if (!this._model.selectionEnd) {
+ this.refresh(true);
+ return;
+ }
+ if (this._activeSelectionMode === 2) {
+ if (this._model.selectionEnd[1] < this._model.selectionStart[1]) {
+ this._model.selectionEnd[0] = 0;
+ }
+ else {
+ this._model.selectionEnd[0] = this._terminal.cols;
+ }
+ }
+ else if (this._activeSelectionMode === 1) {
+ this._selectToWordAt(this._model.selectionEnd);
+ }
+ this._dragScrollAmount = this._getMouseEventScrollAmount(event);
+ if (this._dragScrollAmount > 0) {
+ this._model.selectionEnd[0] = this._terminal.cols;
+ }
+ else if (this._dragScrollAmount < 0) {
+ this._model.selectionEnd[0] = 0;
+ }
+ if (this._model.selectionEnd[1] < this._buffer.lines.length) {
+ var char = this._buffer.lines.get(this._model.selectionEnd[1])[this._model.selectionEnd[0]];
+ if (char && char[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0) {
+ this._model.selectionEnd[0]++;
+ }
+ }
+ if (!previousSelectionEnd ||
+ previousSelectionEnd[0] !== this._model.selectionEnd[0] ||
+ previousSelectionEnd[1] !== this._model.selectionEnd[1]) {
+ this.refresh(true);
+ }
+ };
+ SelectionManager.prototype._dragScroll = function () {
+ if (this._dragScrollAmount) {
+ this._terminal.scrollLines(this._dragScrollAmount, false);
+ if (this._dragScrollAmount > 0) {
+ this._model.selectionEnd = [this._terminal.cols - 1, Math.min(this._terminal.buffer.ydisp + this._terminal.rows, this._terminal.buffer.lines.length - 1)];
+ }
+ else {
+ this._model.selectionEnd = [0, this._terminal.buffer.ydisp];
+ }
+ this.refresh();
+ }
+ };
+ SelectionManager.prototype._onMouseUp = function (event) {
+ var timeElapsed = event.timeStamp - this._mouseDownTimeStamp;
+ this._removeMouseDownListeners();
+ if (this.selectionText.length <= 1 && timeElapsed < ALT_CLICK_MOVE_CURSOR_TIME) {
+ (new AltClickHandler_1.AltClickHandler(event, this._terminal)).move();
+ }
+ else if (this.hasSelection) {
+ this._terminal.emit('selection');
+ }
+ };
+ SelectionManager.prototype._onBufferActivate = function (e) {
+ this.clearSelection();
+ e.inactiveBuffer.lines.off('trim', this._trimListener);
+ e.activeBuffer.lines.on('trim', this._trimListener);
+ };
+ SelectionManager.prototype._convertViewportColToCharacterIndex = function (bufferLine, coords) {
+ var charIndex = coords[0];
+ for (var i = 0; coords[0] >= i; i++) {
+ var char = bufferLine[i];
+ if (char[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0) {
+ charIndex--;
+ }
+ else if (char[Buffer_1.CHAR_DATA_CHAR_INDEX].length > 1 && coords[0] !== i) {
+ charIndex += char[Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ }
+ }
+ return charIndex;
+ };
+ SelectionManager.prototype.setSelection = function (col, row, length) {
+ this._model.clearSelection();
+ this._removeMouseDownListeners();
+ this._model.selectionStart = [col, row];
+ this._model.selectionStartLength = length;
+ this.refresh();
+ };
+ SelectionManager.prototype._getWordAt = function (coords, allowWhitespaceOnlySelection) {
+ if (coords[0] >= this._terminal.cols) {
+ return null;
+ }
+ var bufferLine = this._buffer.lines.get(coords[1]);
+ if (!bufferLine) {
+ return null;
+ }
+ var line = this._buffer.translateBufferLineToString(coords[1], false);
+ var startIndex = this._convertViewportColToCharacterIndex(bufferLine, coords);
+ var endIndex = startIndex;
+ var charOffset = coords[0] - startIndex;
+ var leftWideCharCount = 0;
+ var rightWideCharCount = 0;
+ var leftLongCharOffset = 0;
+ var rightLongCharOffset = 0;
+ if (line.charAt(startIndex) === ' ') {
+ while (startIndex > 0 && line.charAt(startIndex - 1) === ' ') {
+ startIndex--;
+ }
+ while (endIndex < line.length && line.charAt(endIndex + 1) === ' ') {
+ endIndex++;
+ }
+ }
+ else {
+ var startCol = coords[0];
+ var endCol = coords[0];
+ if (bufferLine[startCol][Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0) {
+ leftWideCharCount++;
+ startCol--;
+ }
+ if (bufferLine[endCol][Buffer_1.CHAR_DATA_WIDTH_INDEX] === 2) {
+ rightWideCharCount++;
+ endCol++;
+ }
+ if (bufferLine[endCol][Buffer_1.CHAR_DATA_CHAR_INDEX].length > 1) {
+ rightLongCharOffset += bufferLine[endCol][Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ endIndex += bufferLine[endCol][Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ }
+ while (startCol > 0 && startIndex > 0 && !this._isCharWordSeparator(bufferLine[startCol - 1])) {
+ var char = bufferLine[startCol - 1];
+ if (char[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0) {
+ leftWideCharCount++;
+ startCol--;
+ }
+ else if (char[Buffer_1.CHAR_DATA_CHAR_INDEX].length > 1) {
+ leftLongCharOffset += char[Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ startIndex -= char[Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ }
+ startIndex--;
+ startCol--;
+ }
+ while (endCol < bufferLine.length && endIndex + 1 < line.length && !this._isCharWordSeparator(bufferLine[endCol + 1])) {
+ var char = bufferLine[endCol + 1];
+ if (char[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 2) {
+ rightWideCharCount++;
+ endCol++;
+ }
+ else if (char[Buffer_1.CHAR_DATA_CHAR_INDEX].length > 1) {
+ rightLongCharOffset += char[Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ endIndex += char[Buffer_1.CHAR_DATA_CHAR_INDEX].length - 1;
+ }
+ endIndex++;
+ endCol++;
+ }
+ }
+ endIndex++;
+ var start = startIndex
+ + charOffset
+ - leftWideCharCount
+ + leftLongCharOffset;
+ var length = Math.min(this._terminal.cols, endIndex
+ - startIndex
+ + leftWideCharCount
+ + rightWideCharCount
+ - leftLongCharOffset
+ - rightLongCharOffset);
+ if (!allowWhitespaceOnlySelection && line.slice(startIndex, endIndex).trim() === '') {
+ return null;
+ }
+ return { start: start, length: length };
+ };
+ SelectionManager.prototype._selectWordAt = function (coords, allowWhitespaceOnlySelection) {
+ var wordPosition = this._getWordAt(coords, allowWhitespaceOnlySelection);
+ if (wordPosition) {
+ this._model.selectionStart = [wordPosition.start, coords[1]];
+ this._model.selectionStartLength = wordPosition.length;
+ }
+ };
+ SelectionManager.prototype._selectToWordAt = function (coords) {
+ var wordPosition = this._getWordAt(coords, true);
+ if (wordPosition) {
+ this._model.selectionEnd = [this._model.areSelectionValuesReversed() ? wordPosition.start : (wordPosition.start + wordPosition.length), coords[1]];
+ }
+ };
+ SelectionManager.prototype._isCharWordSeparator = function (charData) {
+ if (charData[Buffer_1.CHAR_DATA_WIDTH_INDEX] === 0) {
+ return false;
+ }
+ return WORD_SEPARATORS.indexOf(charData[Buffer_1.CHAR_DATA_CHAR_INDEX]) >= 0;
+ };
+ SelectionManager.prototype._selectLineAt = function (line) {
+ var wrappedRange = this._buffer.getWrappedRangeForLine(line);
+ this._model.selectionStart = [0, wrappedRange.first];
+ this._model.selectionEnd = [this._terminal.cols, wrappedRange.last];
+ this._model.selectionStartLength = 0;
+ };
+ return SelectionManager;
+}(EventEmitter_1.EventEmitter));
+exports.SelectionManager = SelectionManager;
+
+},{"./Buffer":2,"./EventEmitter":7,"./SelectionModel":11,"./handlers/AltClickHandler":21,"./shared/utils/Browser":44,"./utils/MouseHelper":51}],11:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var SelectionModel = (function () {
+ function SelectionModel(_terminal) {
+ this._terminal = _terminal;
+ this.clearSelection();
+ }
+ SelectionModel.prototype.clearSelection = function () {
+ this.selectionStart = null;
+ this.selectionEnd = null;
+ this.isSelectAllActive = false;
+ this.selectionStartLength = 0;
+ };
+ Object.defineProperty(SelectionModel.prototype, "finalSelectionStart", {
+ get: function () {
+ if (this.isSelectAllActive) {
+ return [0, 0];
+ }
+ if (!this.selectionEnd || !this.selectionStart) {
+ return this.selectionStart;
+ }
+ return this.areSelectionValuesReversed() ? this.selectionEnd : this.selectionStart;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(SelectionModel.prototype, "finalSelectionEnd", {
+ get: function () {
+ if (this.isSelectAllActive) {
+ return [this._terminal.cols, this._terminal.buffer.ybase + this._terminal.rows - 1];
+ }
+ if (!this.selectionStart) {
+ return null;
+ }
+ if (!this.selectionEnd || this.areSelectionValuesReversed()) {
+ return [this.selectionStart[0] + this.selectionStartLength, this.selectionStart[1]];
+ }
+ if (this.selectionStartLength) {
+ if (this.selectionEnd[1] === this.selectionStart[1]) {
+ return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]];
+ }
+ }
+ return this.selectionEnd;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ SelectionModel.prototype.areSelectionValuesReversed = function () {
+ var start = this.selectionStart;
+ var end = this.selectionEnd;
+ if (!start || !end) {
+ return false;
+ }
+ return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]);
+ };
+ SelectionModel.prototype.onTrim = function (amount) {
+ if (this.selectionStart) {
+ this.selectionStart[1] -= amount;
+ }
+ if (this.selectionEnd) {
+ this.selectionEnd[1] -= amount;
+ }
+ if (this.selectionEnd && this.selectionEnd[1] < 0) {
+ this.clearSelection();
+ return true;
+ }
+ if (this.selectionStart && this.selectionStart[1] < 0) {
+ this.selectionStart[1] = 0;
+ }
+ return false;
+ };
+ return SelectionModel;
+}());
+exports.SelectionModel = SelectionModel;
+
+},{}],12:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.DEFAULT_BELL_SOUND = 'data:audio/wav;base64,UklGRigBAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQQBAADpAFgCwAMlBZoG/wdmCcoKRAypDQ8PbRDBEQQTOxRtFYcWlBePGIUZXhoiG88bcBz7HHIdzh0WHlMeZx51HmkeUx4WHs8dah0AHXwc3hs9G4saxRnyGBIYGBcQFv8U4RPAEoYRQBACD70NWwwHC6gJOwjWBloF7gOBAhABkf8b/qv8R/ve+Xf4Ife79W/0JfPZ8Z/wde9N7ijtE+wU6xvqM+lb6H7nw+YX5mrlxuQz5Mzje+Ma49fioeKD4nXiYeJy4pHitOL04j/jn+MN5IPkFOWs5U3mDefM55/ogOl36m7rdOyE7abuyu8D8Unyj/Pg9D/2qfcb+Yn6/vuK/Qj/lAAlAg==';
+var SoundManager = (function () {
+ function SoundManager(_terminal) {
+ this._terminal = _terminal;
+ }
+ SoundManager.prototype.playBellSound = function () {
+ var audioContextCtor = window.AudioContext || window.webkitAudioContext;
+ if (!this._audioContext && audioContextCtor) {
+ this._audioContext = new audioContextCtor();
+ }
+ if (this._audioContext) {
+ var bellAudioSource_1 = this._audioContext.createBufferSource();
+ var context_1 = this._audioContext;
+ this._audioContext.decodeAudioData(this._base64ToArrayBuffer(this._removeMimeType(this._terminal.options.bellSound)), function (buffer) {
+ bellAudioSource_1.buffer = buffer;
+ bellAudioSource_1.connect(context_1.destination);
+ bellAudioSource_1.start(0);
+ });
+ }
+ else {
+ console.warn('Sorry, but the Web Audio API is not supported by your browser. Please, consider upgrading to the latest version');
+ }
+ };
+ SoundManager.prototype._base64ToArrayBuffer = function (base64) {
+ var binaryString = window.atob(base64);
+ var len = binaryString.length;
+ var bytes = new Uint8Array(len);
+ for (var i = 0; i < len; i++) {
+ bytes[i] = binaryString.charCodeAt(i);
+ }
+ return bytes.buffer;
+ };
+ SoundManager.prototype._removeMimeType = function (dataURI) {
+ var splitUri = dataURI.split(',');
+ return splitUri[1];
+ };
+ return SoundManager;
+}());
+exports.SoundManager = SoundManager;
+
+},{}],13:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.blankLine = 'Blank line';
+exports.promptLabel = 'Terminal input';
+exports.tooMuchOutput = 'Too much output to announce, navigate to rows manually to read';
+
+},{}],14:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var BufferSet_1 = require("./BufferSet");
+var Buffer_1 = require("./Buffer");
+var CompositionHelper_1 = require("./CompositionHelper");
+var EventEmitter_1 = require("./EventEmitter");
+var Viewport_1 = require("./Viewport");
+var Clipboard_1 = require("./handlers/Clipboard");
+var EscapeSequences_1 = require("./common/data/EscapeSequences");
+var InputHandler_1 = require("./InputHandler");
+var Renderer_1 = require("./renderer/Renderer");
+var Linkifier_1 = require("./Linkifier");
+var SelectionManager_1 = require("./SelectionManager");
+var CharMeasure_1 = require("./ui/CharMeasure");
+var Browser = require("./shared/utils/Browser");
+var Lifecycle_1 = require("./ui/Lifecycle");
+var Strings = require("./Strings");
+var MouseHelper_1 = require("./utils/MouseHelper");
+var Clone_1 = require("./utils/Clone");
+var SoundManager_1 = require("./SoundManager");
+var ColorManager_1 = require("./renderer/ColorManager");
+var MouseZoneManager_1 = require("./ui/MouseZoneManager");
+var AccessibilityManager_1 = require("./AccessibilityManager");
+var ScreenDprMonitor_1 = require("./ui/ScreenDprMonitor");
+var CharAtlasCache_1 = require("./renderer/atlas/CharAtlasCache");
+var DomRenderer_1 = require("./renderer/dom/DomRenderer");
+var Keyboard_1 = require("./core/input/Keyboard");
+var document = (typeof window !== 'undefined') ? window.document : null;
+var WRITE_BUFFER_PAUSE_THRESHOLD = 5;
+var WRITE_BATCH_SIZE = 300;
+var CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows', 'rendererType'];
+var DEFAULT_OPTIONS = {
+ cols: 80,
+ rows: 24,
+ convertEol: false,
+ termName: 'xterm',
+ cursorBlink: false,
+ cursorStyle: 'block',
+ bellSound: SoundManager_1.DEFAULT_BELL_SOUND,
+ bellStyle: 'none',
+ drawBoldTextInBrightColors: true,
+ enableBold: true,
+ experimentalCharAtlas: 'static',
+ fontFamily: 'courier-new, courier, monospace',
+ fontSize: 15,
+ fontWeight: 'normal',
+ fontWeightBold: 'bold',
+ lineHeight: 1.0,
+ letterSpacing: 0,
+ scrollback: 1000,
+ screenKeys: false,
+ screenReaderMode: false,
+ debug: false,
+ macOptionIsMeta: false,
+ macOptionClickForcesSelection: false,
+ cancelEvents: false,
+ disableStdin: false,
+ useFlowControl: false,
+ allowTransparency: false,
+ tabStopWidth: 8,
+ theme: null,
+ rightClickSelectsWord: Browser.isMac,
+ rendererType: 'canvas'
+};
+var Terminal = (function (_super) {
+ __extends(Terminal, _super);
+ function Terminal(options) {
+ if (options === void 0) { options = {}; }
+ var _this = _super.call(this) || this;
+ _this.browser = Browser;
+ _this.options = Clone_1.clone(options);
+ _this._setup();
+ return _this;
+ }
+ Terminal.prototype.dispose = function () {
+ _super.prototype.dispose.call(this);
+ this._customKeyEventHandler = null;
+ CharAtlasCache_1.removeTerminalFromCache(this);
+ this.handler = function () { };
+ this.write = function () { };
+ if (this.element && this.element.parentNode) {
+ this.element.parentNode.removeChild(this.element);
+ }
+ };
+ Terminal.prototype.destroy = function () {
+ this.dispose();
+ };
+ Terminal.prototype._setup = function () {
+ var _this = this;
+ Object.keys(DEFAULT_OPTIONS).forEach(function (key) {
+ if (_this.options[key] == null) {
+ _this.options[key] = DEFAULT_OPTIONS[key];
+ }
+ });
+ this._parent = document ? document.body : null;
+ this.cols = this.options.cols;
+ this.rows = this.options.rows;
+ if (this.options.handler) {
+ this.on('data', this.options.handler);
+ }
+ this.cursorState = 0;
+ this.cursorHidden = false;
+ this._sendDataQueue = '';
+ this._customKeyEventHandler = null;
+ this.applicationKeypad = false;
+ this.applicationCursor = false;
+ this.originMode = false;
+ this.insertMode = false;
+ this.wraparoundMode = true;
+ this.bracketedPasteMode = false;
+ this.charset = null;
+ this.gcharset = null;
+ this.glevel = 0;
+ this.charsets = [null];
+ this.curAttr = Buffer_1.DEFAULT_ATTR;
+ this.params = [];
+ this.currentParam = 0;
+ this.writeBuffer = [];
+ this._writeInProgress = false;
+ this._xoffSentToCatchUp = false;
+ this._userScrolling = false;
+ this._inputHandler = new InputHandler_1.InputHandler(this);
+ this.register(this._inputHandler);
+ this.renderer = this.renderer || null;
+ this.selectionManager = this.selectionManager || null;
+ this.linkifier = this.linkifier || new Linkifier_1.Linkifier(this);
+ this._mouseZoneManager = this._mouseZoneManager || null;
+ this.soundManager = this.soundManager || new SoundManager_1.SoundManager(this);
+ this.buffers = new BufferSet_1.BufferSet(this);
+ if (this.selectionManager) {
+ this.selectionManager.clearSelection();
+ this.selectionManager.initBuffersListeners();
+ }
+ };
+ Object.defineProperty(Terminal.prototype, "buffer", {
+ get: function () {
+ return this.buffers.active;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Terminal.prototype.eraseAttr = function () {
+ return (Buffer_1.DEFAULT_ATTR & ~0x1ff) | (this.curAttr & 0x1ff);
+ };
+ Terminal.prototype.focus = function () {
+ if (this.textarea) {
+ this.textarea.focus();
+ }
+ };
+ Object.defineProperty(Terminal.prototype, "isFocused", {
+ get: function () {
+ return document.activeElement === this.textarea;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Terminal.prototype.getOption = function (key) {
+ if (!(key in DEFAULT_OPTIONS)) {
+ throw new Error('No option with key "' + key + '"');
+ }
+ return this.options[key];
+ };
+ Terminal.prototype.setOption = function (key, value) {
+ if (!(key in DEFAULT_OPTIONS)) {
+ throw new Error('No option with key "' + key + '"');
+ }
+ if (CONSTRUCTOR_ONLY_OPTIONS.indexOf(key) !== -1) {
+ console.error("Option \"" + key + "\" can only be set in the constructor");
+ }
+ switch (key) {
+ case 'bellStyle':
+ if (!value) {
+ value = 'none';
+ }
+ break;
+ case 'cursorStyle':
+ if (!value) {
+ value = 'block';
+ }
+ break;
+ case 'fontWeight':
+ if (!value) {
+ value = 'normal';
+ }
+ break;
+ case 'fontWeightBold':
+ if (!value) {
+ value = 'bold';
+ }
+ break;
+ case 'lineHeight':
+ if (value < 1) {
+ console.warn(key + " cannot be less than 1, value: " + value);
+ return;
+ }
+ case 'tabStopWidth':
+ if (value < 1) {
+ console.warn(key + " cannot be less than 1, value: " + value);
+ return;
+ }
+ break;
+ case 'theme':
+ if (this.renderer) {
+ this._setTheme(value);
+ return;
+ }
+ break;
+ case 'scrollback':
+ value = Math.min(value, Buffer_1.MAX_BUFFER_SIZE);
+ if (value < 0) {
+ console.warn(key + " cannot be less than 0, value: " + value);
+ return;
+ }
+ if (this.options[key] !== value) {
+ var newBufferLength = this.rows + value;
+ if (this.buffer.lines.length > newBufferLength) {
+ var amountToTrim = this.buffer.lines.length - newBufferLength;
+ var needsRefresh = (this.buffer.ydisp - amountToTrim < 0);
+ this.buffer.lines.trimStart(amountToTrim);
+ this.buffer.ybase = Math.max(this.buffer.ybase - amountToTrim, 0);
+ this.buffer.ydisp = Math.max(this.buffer.ydisp - amountToTrim, 0);
+ if (needsRefresh) {
+ this.refresh(0, this.rows - 1);
+ }
+ }
+ }
+ break;
+ }
+ this.options[key] = value;
+ switch (key) {
+ case 'fontFamily':
+ case 'fontSize':
+ if (this.renderer) {
+ this.renderer.clear();
+ this.charMeasure.measure(this.options);
+ }
+ break;
+ case 'drawBoldTextInBrightColors':
+ case 'experimentalCharAtlas':
+ case 'enableBold':
+ case 'letterSpacing':
+ case 'lineHeight':
+ case 'fontWeight':
+ case 'fontWeightBold':
+ if (this.renderer) {
+ this.renderer.clear();
+ this.renderer.onResize(this.cols, this.rows);
+ this.refresh(0, this.rows - 1);
+ }
+ case 'scrollback':
+ this.buffers.resize(this.cols, this.rows);
+ if (this.viewport) {
+ this.viewport.syncScrollArea();
+ }
+ break;
+ case 'screenReaderMode':
+ if (value) {
+ if (!this._accessibilityManager) {
+ this._accessibilityManager = new AccessibilityManager_1.AccessibilityManager(this);
+ }
+ }
+ else {
+ if (this._accessibilityManager) {
+ this._accessibilityManager.dispose();
+ this._accessibilityManager = null;
+ }
+ }
+ break;
+ case 'tabStopWidth':
+ this.buffers.setupTabStops();
+ break;
+ }
+ if (this.renderer) {
+ this.renderer.onOptionsChanged();
+ }
+ };
+ Terminal.prototype._onTextAreaFocus = function () {
+ if (this.sendFocus) {
+ this.send(EscapeSequences_1.C0.ESC + '[I');
+ }
+ this.element.classList.add('focus');
+ this.showCursor();
+ this.emit('focus');
+ };
+ Terminal.prototype.blur = function () {
+ return this.textarea.blur();
+ };
+ Terminal.prototype._onTextAreaBlur = function () {
+ this.textarea.value = '';
+ this.refresh(this.buffer.y, this.buffer.y);
+ if (this.sendFocus) {
+ this.send(EscapeSequences_1.C0.ESC + '[O');
+ }
+ this.element.classList.remove('focus');
+ this.emit('blur');
+ };
+ Terminal.prototype._initGlobal = function () {
+ var _this = this;
+ this._bindKeys();
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'copy', function (event) {
+ if (!_this.hasSelection()) {
+ return;
+ }
+ Clipboard_1.copyHandler(event, _this, _this.selectionManager);
+ }));
+ var pasteHandlerWrapper = function (event) { return Clipboard_1.pasteHandler(event, _this); };
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'paste', pasteHandlerWrapper));
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'paste', pasteHandlerWrapper));
+ if (Browser.isFirefox) {
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'mousedown', function (event) {
+ if (event.button === 2) {
+ Clipboard_1.rightClickHandler(event, _this.textarea, _this.selectionManager, _this.options.rightClickSelectsWord);
+ }
+ }));
+ }
+ else {
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'contextmenu', function (event) {
+ Clipboard_1.rightClickHandler(event, _this.textarea, _this.selectionManager, _this.options.rightClickSelectsWord);
+ }));
+ }
+ if (Browser.isLinux) {
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'auxclick', function (event) {
+ if (event.button === 1) {
+ Clipboard_1.moveTextAreaUnderMouseCursor(event, _this.textarea);
+ }
+ }));
+ }
+ };
+ Terminal.prototype._bindKeys = function () {
+ var _this = this;
+ var self = this;
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'keydown', function (ev) {
+ if (document.activeElement !== this) {
+ return;
+ }
+ self._keyDown(ev);
+ }, true));
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'keypress', function (ev) {
+ if (document.activeElement !== this) {
+ return;
+ }
+ self._keyPress(ev);
+ }, true));
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'keyup', function (ev) {
+ if (!wasModifierKeyOnlyEvent(ev)) {
+ _this.focus();
+ }
+ self._keyUp(ev);
+ }, true));
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'keydown', function (ev) { return _this._keyDown(ev); }, true));
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'keypress', function (ev) { return _this._keyPress(ev); }, true));
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'compositionstart', function () { return _this._compositionHelper.compositionstart(); }));
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'compositionupdate', function (e) { return _this._compositionHelper.compositionupdate(e); }));
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'compositionend', function () { return _this._compositionHelper.compositionend(); }));
+ this.register(this.addDisposableListener('refresh', function () { return _this._compositionHelper.updateCompositionElements(); }));
+ this.register(this.addDisposableListener('refresh', function (data) { return _this._queueLinkification(data.start, data.end); }));
+ };
+ Terminal.prototype.open = function (parent) {
+ var _this = this;
+ this._parent = parent || this._parent;
+ if (!this._parent) {
+ throw new Error('Terminal requires a parent element.');
+ }
+ this._context = this._parent.ownerDocument.defaultView;
+ this._document = this._parent.ownerDocument;
+ this._screenDprMonitor = new ScreenDprMonitor_1.ScreenDprMonitor();
+ this._screenDprMonitor.setListener(function () { return _this.emit('dprchange', window.devicePixelRatio); });
+ this.register(this._screenDprMonitor);
+ this.element = this._document.createElement('div');
+ this.element.dir = 'ltr';
+ this.element.classList.add('terminal');
+ this.element.classList.add('xterm');
+ this.element.setAttribute('tabindex', '0');
+ this._parent.appendChild(this.element);
+ var fragment = document.createDocumentFragment();
+ this._viewportElement = document.createElement('div');
+ this._viewportElement.classList.add('xterm-viewport');
+ fragment.appendChild(this._viewportElement);
+ this._viewportScrollArea = document.createElement('div');
+ this._viewportScrollArea.classList.add('xterm-scroll-area');
+ this._viewportElement.appendChild(this._viewportScrollArea);
+ this.screenElement = document.createElement('div');
+ this.screenElement.classList.add('xterm-screen');
+ this._helperContainer = document.createElement('div');
+ this._helperContainer.classList.add('xterm-helpers');
+ this.screenElement.appendChild(this._helperContainer);
+ fragment.appendChild(this.screenElement);
+ this._mouseZoneManager = new MouseZoneManager_1.MouseZoneManager(this);
+ this.register(this._mouseZoneManager);
+ this.register(this.addDisposableListener('scroll', function () { return _this._mouseZoneManager.clearAll(); }));
+ this.linkifier.attachToDom(this._mouseZoneManager);
+ this.textarea = document.createElement('textarea');
+ this.textarea.classList.add('xterm-helper-textarea');
+ this.textarea.setAttribute('aria-label', Strings.promptLabel);
+ this.textarea.setAttribute('aria-multiline', 'false');
+ this.textarea.setAttribute('autocorrect', 'off');
+ this.textarea.setAttribute('autocapitalize', 'off');
+ this.textarea.setAttribute('spellcheck', 'false');
+ this.textarea.tabIndex = 0;
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'focus', function () { return _this._onTextAreaFocus(); }));
+ this.register(Lifecycle_1.addDisposableDomListener(this.textarea, 'blur', function () { return _this._onTextAreaBlur(); }));
+ this._helperContainer.appendChild(this.textarea);
+ this._compositionView = document.createElement('div');
+ this._compositionView.classList.add('composition-view');
+ this._compositionHelper = new CompositionHelper_1.CompositionHelper(this.textarea, this._compositionView, this);
+ this._helperContainer.appendChild(this._compositionView);
+ this.charMeasure = new CharMeasure_1.CharMeasure(document, this._helperContainer);
+ this.element.appendChild(fragment);
+ switch (this.options.rendererType) {
+ case 'canvas':
+ this.renderer = new Renderer_1.Renderer(this, this.options.theme);
+ break;
+ case 'dom':
+ this.renderer = new DomRenderer_1.DomRenderer(this, this.options.theme);
+ break;
+ default: throw new Error("Unrecognized rendererType \"" + this.options.rendererType + "\"");
+ }
+ this.register(this.renderer);
+ this.options.theme = null;
+ this.viewport = new Viewport_1.Viewport(this, this._viewportElement, this._viewportScrollArea, this.charMeasure);
+ this.viewport.onThemeChanged(this.renderer.colorManager.colors);
+ this.register(this.viewport);
+ this.register(this.addDisposableListener('cursormove', function () { return _this.renderer.onCursorMove(); }));
+ this.register(this.addDisposableListener('resize', function () { return _this.renderer.onResize(_this.cols, _this.rows); }));
+ this.register(this.addDisposableListener('blur', function () { return _this.renderer.onBlur(); }));
+ this.register(this.addDisposableListener('focus', function () { return _this.renderer.onFocus(); }));
+ this.register(this.addDisposableListener('dprchange', function () { return _this.renderer.onWindowResize(window.devicePixelRatio); }));
+ this.register(Lifecycle_1.addDisposableDomListener(window, 'resize', function () { return _this.renderer.onWindowResize(window.devicePixelRatio); }));
+ this.register(this.charMeasure.addDisposableListener('charsizechanged', function () { return _this.renderer.onCharSizeChanged(); }));
+ this.register(this.renderer.addDisposableListener('resize', function (dimensions) { return _this.viewport.syncScrollArea(); }));
+ this.selectionManager = new SelectionManager_1.SelectionManager(this, this.charMeasure);
+ this.register(Lifecycle_1.addDisposableDomListener(this.element, 'mousedown', function (e) { return _this.selectionManager.onMouseDown(e); }));
+ this.register(this.selectionManager.addDisposableListener('refresh', function (data) { return _this.renderer.onSelectionChanged(data.start, data.end, data.columnSelectMode); }));
+ this.register(this.selectionManager.addDisposableListener('newselection', function (text) {
+ _this.textarea.value = text;
+ _this.textarea.focus();
+ _this.textarea.select();
+ }));
+ this.register(this.addDisposableListener('scroll', function () {
+ _this.viewport.syncScrollArea();
+ _this.selectionManager.refresh();
+ }));
+ this.register(Lifecycle_1.addDisposableDomListener(this._viewportElement, 'scroll', function () { return _this.selectionManager.refresh(); }));
+ this.mouseHelper = new MouseHelper_1.MouseHelper(this.renderer);
+ if (this.options.screenReaderMode) {
+ this._accessibilityManager = new AccessibilityManager_1.AccessibilityManager(this);
+ }
+ this.charMeasure.measure(this.options);
+ this.refresh(0, this.rows - 1);
+ this._initGlobal();
+ this.bindMouse();
+ };
+ Terminal.prototype._setTheme = function (theme) {
+ var colors = this.renderer.setTheme(theme);
+ if (this.viewport) {
+ this.viewport.onThemeChanged(colors);
+ }
+ };
+ Terminal.prototype.bindMouse = function () {
+ var _this = this;
+ var el = this.element;
+ var self = this;
+ var pressed = 32;
+ function sendButton(ev) {
+ var button;
+ var pos;
+ button = getButton(ev);
+ pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
+ if (!pos)
+ return;
+ sendEvent(button, pos);
+ switch (ev.overrideType || ev.type) {
+ case 'mousedown':
+ pressed = button;
+ break;
+ case 'mouseup':
+ pressed = 32;
+ break;
+ case 'wheel':
+ break;
+ }
+ }
+ function sendMove(ev) {
+ var button = pressed;
+ var pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
+ if (!pos)
+ return;
+ button += 32;
+ sendEvent(button, pos);
+ }
+ function encode(data, ch) {
+ if (!self.utfMouse) {
+ if (ch === 255) {
+ data.push(0);
+ return;
+ }
+ if (ch > 127)
+ ch = 127;
+ data.push(ch);
+ }
+ else {
+ if (ch === 2047) {
+ data.push(0);
+ return;
+ }
+ if (ch < 127) {
+ data.push(ch);
+ }
+ else {
+ if (ch > 2047)
+ ch = 2047;
+ data.push(0xC0 | (ch >> 6));
+ data.push(0x80 | (ch & 0x3F));
+ }
+ }
+ }
+ function sendEvent(button, pos) {
+ if (self._vt300Mouse) {
+ button &= 3;
+ pos.x -= 32;
+ pos.y -= 32;
+ var data_1 = EscapeSequences_1.C0.ESC + '[24';
+ if (button === 0)
+ data_1 += '1';
+ else if (button === 1)
+ data_1 += '3';
+ else if (button === 2)
+ data_1 += '5';
+ else if (button === 3)
+ return;
+ else
+ data_1 += '0';
+ data_1 += '~[' + pos.x + ',' + pos.y + ']\r';
+ self.send(data_1);
+ return;
+ }
+ if (self._decLocator) {
+ button &= 3;
+ pos.x -= 32;
+ pos.y -= 32;
+ if (button === 0)
+ button = 2;
+ else if (button === 1)
+ button = 4;
+ else if (button === 2)
+ button = 6;
+ else if (button === 3)
+ button = 3;
+ self.send(EscapeSequences_1.C0.ESC + '['
+ + button
+ + ';'
+ + (button === 3 ? 4 : 0)
+ + ';'
+ + pos.y
+ + ';'
+ + pos.x
+ + ';'
+ + pos.page || 0
+ + '&w');
+ return;
+ }
+ if (self.urxvtMouse) {
+ pos.x -= 32;
+ pos.y -= 32;
+ pos.x++;
+ pos.y++;
+ self.send(EscapeSequences_1.C0.ESC + '[' + button + ';' + pos.x + ';' + pos.y + 'M');
+ return;
+ }
+ if (self.sgrMouse) {
+ pos.x -= 32;
+ pos.y -= 32;
+ self.send(EscapeSequences_1.C0.ESC + '[<'
+ + (((button & 3) === 3 ? button & ~3 : button) - 32)
+ + ';'
+ + pos.x
+ + ';'
+ + pos.y
+ + ((button & 3) === 3 ? 'm' : 'M'));
+ return;
+ }
+ var data = [];
+ encode(data, button);
+ encode(data, pos.x);
+ encode(data, pos.y);
+ self.send(EscapeSequences_1.C0.ESC + '[M' + String.fromCharCode.apply(String, data));
+ }
+ function getButton(ev) {
+ var button;
+ var shift;
+ var meta;
+ var ctrl;
+ var mod;
+ switch (ev.overrideType || ev.type) {
+ case 'mousedown':
+ button = ev.button != null
+ ? +ev.button
+ : ev.which != null
+ ? ev.which - 1
+ : null;
+ if (Browser.isMSIE) {
+ button = button === 1 ? 0 : button === 4 ? 1 : button;
+ }
+ break;
+ case 'mouseup':
+ button = 3;
+ break;
+ case 'DOMMouseScroll':
+ button = ev.detail < 0
+ ? 64
+ : 65;
+ break;
+ case 'wheel':
+ button = ev.wheelDeltaY > 0
+ ? 64
+ : 65;
+ break;
+ }
+ shift = ev.shiftKey ? 4 : 0;
+ meta = ev.metaKey ? 8 : 0;
+ ctrl = ev.ctrlKey ? 16 : 0;
+ mod = shift | meta | ctrl;
+ if (self.vt200Mouse) {
+ mod &= ctrl;
+ }
+ else if (!self.normalMouse) {
+ mod = 0;
+ }
+ button = (32 + (mod << 2)) + button;
+ return button;
+ }
+ this.register(Lifecycle_1.addDisposableDomListener(el, 'mousedown', function (ev) {
+ ev.preventDefault();
+ _this.focus();
+ if (!_this.mouseEvents || _this.selectionManager.shouldForceSelection(ev)) {
+ return;
+ }
+ sendButton(ev);
+ if (_this.vt200Mouse) {
+ ev.overrideType = 'mouseup';
+ sendButton(ev);
+ return _this.cancel(ev);
+ }
+ var moveHandler;
+ if (_this.normalMouse) {
+ moveHandler = function (event) {
+ if (!_this.normalMouse) {
+ return;
+ }
+ sendMove(event);
+ };
+ _this._document.addEventListener('mousemove', moveHandler);
+ }
+ var handler = function (ev) {
+ if (_this.normalMouse && !_this.x10Mouse) {
+ sendButton(ev);
+ }
+ if (moveHandler) {
+ _this._document.removeEventListener('mousemove', moveHandler);
+ moveHandler = null;
+ }
+ _this._document.removeEventListener('mouseup', handler);
+ return _this.cancel(ev);
+ };
+ _this._document.addEventListener('mouseup', handler);
+ return _this.cancel(ev);
+ }));
+ this.register(Lifecycle_1.addDisposableDomListener(el, 'wheel', function (ev) {
+ if (!_this.mouseEvents) {
+ if (!_this.buffer.hasScrollback) {
+ var amount = _this.viewport.getLinesScrolled(ev);
+ if (amount === 0) {
+ return;
+ }
+ var sequence = EscapeSequences_1.C0.ESC + (_this.applicationCursor ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B');
+ var data = '';
+ for (var i = 0; i < Math.abs(amount); i++) {
+ data += sequence;
+ }
+ _this.send(data);
+ }
+ return;
+ }
+ if (_this.x10Mouse || _this._vt300Mouse || _this._decLocator)
+ return;
+ sendButton(ev);
+ ev.preventDefault();
+ }));
+ this.register(Lifecycle_1.addDisposableDomListener(el, 'wheel', function (ev) {
+ if (_this.mouseEvents)
+ return;
+ _this.viewport.onWheel(ev);
+ return _this.cancel(ev);
+ }));
+ this.register(Lifecycle_1.addDisposableDomListener(el, 'touchstart', function (ev) {
+ if (_this.mouseEvents)
+ return;
+ _this.viewport.onTouchStart(ev);
+ return _this.cancel(ev);
+ }));
+ this.register(Lifecycle_1.addDisposableDomListener(el, 'touchmove', function (ev) {
+ if (_this.mouseEvents)
+ return;
+ _this.viewport.onTouchMove(ev);
+ return _this.cancel(ev);
+ }));
+ };
+ Terminal.prototype.refresh = function (start, end) {
+ if (this.renderer) {
+ this.renderer.refreshRows(start, end);
+ }
+ };
+ Terminal.prototype._queueLinkification = function (start, end) {
+ if (this.linkifier) {
+ this.linkifier.linkifyRows(start, end);
+ }
+ };
+ Terminal.prototype.updateCursorStyle = function (ev) {
+ if (this.selectionManager && this.selectionManager.shouldColumnSelect(ev)) {
+ this.element.classList.add('xterm-cursor-crosshair');
+ }
+ else {
+ this.element.classList.remove('xterm-cursor-crosshair');
+ }
+ };
+ Terminal.prototype.showCursor = function () {
+ if (!this.cursorState) {
+ this.cursorState = 1;
+ this.refresh(this.buffer.y, this.buffer.y);
+ }
+ };
+ Terminal.prototype.scroll = function (isWrapped) {
+ var newLine = this.blankLine(undefined, isWrapped);
+ var topRow = this.buffer.ybase + this.buffer.scrollTop;
+ var bottomRow = this.buffer.ybase + this.buffer.scrollBottom;
+ if (this.buffer.scrollTop === 0) {
+ var willBufferBeTrimmed = this.buffer.lines.length === this.buffer.lines.maxLength;
+ if (bottomRow === this.buffer.lines.length - 1) {
+ this.buffer.lines.push(newLine);
+ }
+ else {
+ this.buffer.lines.splice(bottomRow + 1, 0, newLine);
+ }
+ if (!willBufferBeTrimmed) {
+ this.buffer.ybase++;
+ if (!this._userScrolling) {
+ this.buffer.ydisp++;
+ }
+ }
+ else {
+ if (this._userScrolling) {
+ this.buffer.ydisp = Math.max(this.buffer.ydisp - 1, 0);
+ }
+ }
+ }
+ else {
+ var scrollRegionHeight = bottomRow - topRow + 1;
+ this.buffer.lines.shiftElements(topRow + 1, scrollRegionHeight - 1, -1);
+ this.buffer.lines.set(bottomRow, newLine);
+ }
+ if (!this._userScrolling) {
+ this.buffer.ydisp = this.buffer.ybase;
+ }
+ this.updateRange(this.buffer.scrollTop);
+ this.updateRange(this.buffer.scrollBottom);
+ this.emit('scroll', this.buffer.ydisp);
+ };
+ Terminal.prototype.scrollLines = function (disp, suppressScrollEvent) {
+ if (disp < 0) {
+ if (this.buffer.ydisp === 0) {
+ return;
+ }
+ this._userScrolling = true;
+ }
+ else if (disp + this.buffer.ydisp >= this.buffer.ybase) {
+ this._userScrolling = false;
+ }
+ var oldYdisp = this.buffer.ydisp;
+ this.buffer.ydisp = Math.max(Math.min(this.buffer.ydisp + disp, this.buffer.ybase), 0);
+ if (oldYdisp === this.buffer.ydisp) {
+ return;
+ }
+ if (!suppressScrollEvent) {
+ this.emit('scroll', this.buffer.ydisp);
+ }
+ this.refresh(0, this.rows - 1);
+ };
+ Terminal.prototype.scrollPages = function (pageCount) {
+ this.scrollLines(pageCount * (this.rows - 1));
+ };
+ Terminal.prototype.scrollToTop = function () {
+ this.scrollLines(-this.buffer.ydisp);
+ };
+ Terminal.prototype.scrollToBottom = function () {
+ this.scrollLines(this.buffer.ybase - this.buffer.ydisp);
+ };
+ Terminal.prototype.scrollToLine = function (line) {
+ var scrollAmount = line - this.buffer.ydisp;
+ if (scrollAmount !== 0) {
+ this.scrollLines(scrollAmount);
+ }
+ };
+ Terminal.prototype.write = function (data) {
+ var _this = this;
+ if (!data) {
+ return;
+ }
+ this.writeBuffer.push(data);
+ if (this.options.useFlowControl && !this._xoffSentToCatchUp && this.writeBuffer.length >= WRITE_BUFFER_PAUSE_THRESHOLD) {
+ this.send(EscapeSequences_1.C0.DC3);
+ this._xoffSentToCatchUp = true;
+ }
+ if (!this._writeInProgress && this.writeBuffer.length > 0) {
+ this._writeInProgress = true;
+ setTimeout(function () {
+ _this._innerWrite();
+ });
+ }
+ };
+ Terminal.prototype._innerWrite = function () {
+ var _this = this;
+ var writeBatch = this.writeBuffer.splice(0, WRITE_BATCH_SIZE);
+ while (writeBatch.length > 0) {
+ var data = writeBatch.shift();
+ if (this._xoffSentToCatchUp && writeBatch.length === 0 && this.writeBuffer.length === 0) {
+ this.send(EscapeSequences_1.C0.DC1);
+ this._xoffSentToCatchUp = false;
+ }
+ this._refreshStart = this.buffer.y;
+ this._refreshEnd = this.buffer.y;
+ this._inputHandler.parse(data);
+ this.updateRange(this.buffer.y);
+ this.refresh(this._refreshStart, this._refreshEnd);
+ }
+ if (this.writeBuffer.length > 0) {
+ setTimeout(function () { return _this._innerWrite(); }, 0);
+ }
+ else {
+ this._writeInProgress = false;
+ }
+ };
+ Terminal.prototype.writeln = function (data) {
+ this.write(data + '\r\n');
+ };
+ Terminal.prototype.attachCustomKeyEventHandler = function (customKeyEventHandler) {
+ this._customKeyEventHandler = customKeyEventHandler;
+ };
+ Terminal.prototype.registerLinkMatcher = function (regex, handler, options) {
+ var matcherId = this.linkifier.registerLinkMatcher(regex, handler, options);
+ this.refresh(0, this.rows - 1);
+ return matcherId;
+ };
+ Terminal.prototype.deregisterLinkMatcher = function (matcherId) {
+ if (this.linkifier.deregisterLinkMatcher(matcherId)) {
+ this.refresh(0, this.rows - 1);
+ }
+ };
+ Object.defineProperty(Terminal.prototype, "markers", {
+ get: function () {
+ return this.buffer.markers;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Terminal.prototype.addMarker = function (cursorYOffset) {
+ if (this.buffer !== this.buffers.normal) {
+ return;
+ }
+ return this.buffer.addMarker(this.buffer.ybase + this.buffer.y + cursorYOffset);
+ };
+ Terminal.prototype.hasSelection = function () {
+ return this.selectionManager ? this.selectionManager.hasSelection : false;
+ };
+ Terminal.prototype.getSelection = function () {
+ return this.selectionManager ? this.selectionManager.selectionText : '';
+ };
+ Terminal.prototype.clearSelection = function () {
+ if (this.selectionManager) {
+ this.selectionManager.clearSelection();
+ }
+ };
+ Terminal.prototype.selectAll = function () {
+ if (this.selectionManager) {
+ this.selectionManager.selectAll();
+ }
+ };
+ Terminal.prototype.selectLines = function (start, end) {
+ if (this.selectionManager) {
+ this.selectionManager.selectLines(start, end);
+ }
+ };
+ Terminal.prototype._keyDown = function (event) {
+ if (this._customKeyEventHandler && this._customKeyEventHandler(event) === false) {
+ return false;
+ }
+ if (!this._compositionHelper.keydown(event)) {
+ if (this.buffer.ybase !== this.buffer.ydisp) {
+ this.scrollToBottom();
+ }
+ return false;
+ }
+ var result = Keyboard_1.evaluateKeyboardEvent(event, this.applicationCursor, this.browser.isMac, this.options.macOptionIsMeta);
+ this.updateCursorStyle(event);
+ if (result.type === 3 || result.type === 2) {
+ var scrollCount = this.rows - 1;
+ this.scrollLines(result.type === 2 ? -scrollCount : scrollCount);
+ return this.cancel(event, true);
+ }
+ if (result.type === 1) {
+ this.selectAll();
+ }
+ if (this._isThirdLevelShift(this.browser, event)) {
+ return true;
+ }
+ if (result.cancel) {
+ this.cancel(event, true);
+ }
+ if (!result.key) {
+ return true;
+ }
+ this.emit('keydown', event);
+ this.emit('key', result.key, event);
+ this.showCursor();
+ this.handler(result.key);
+ return this.cancel(event, true);
+ };
+ Terminal.prototype._isThirdLevelShift = function (browser, ev) {
+ var thirdLevelKey = (browser.isMac && !this.options.macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
+ (browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
+ if (ev.type === 'keypress') {
+ return thirdLevelKey;
+ }
+ return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
+ };
+ Terminal.prototype.setgLevel = function (g) {
+ this.glevel = g;
+ this.charset = this.charsets[g];
+ };
+ Terminal.prototype.setgCharset = function (g, charset) {
+ this.charsets[g] = charset;
+ if (this.glevel === g) {
+ this.charset = charset;
+ }
+ };
+ Terminal.prototype._keyUp = function (ev) {
+ this.updateCursorStyle(ev);
+ };
+ Terminal.prototype._keyPress = function (ev) {
+ var key;
+ if (this._customKeyEventHandler && this._customKeyEventHandler(ev) === false) {
+ return false;
+ }
+ this.cancel(ev);
+ if (ev.charCode) {
+ key = ev.charCode;
+ }
+ else if (ev.which == null) {
+ key = ev.keyCode;
+ }
+ else if (ev.which !== 0 && ev.charCode !== 0) {
+ key = ev.which;
+ }
+ else {
+ return false;
+ }
+ if (!key || ((ev.altKey || ev.ctrlKey || ev.metaKey) && !this._isThirdLevelShift(this.browser, ev))) {
+ return false;
+ }
+ key = String.fromCharCode(key);
+ this.emit('keypress', key, ev);
+ this.emit('key', key, ev);
+ this.showCursor();
+ this.handler(key);
+ return true;
+ };
+ Terminal.prototype.send = function (data) {
+ var _this = this;
+ if (!this._sendDataQueue) {
+ setTimeout(function () {
+ _this.handler(_this._sendDataQueue);
+ _this._sendDataQueue = '';
+ }, 1);
+ }
+ this._sendDataQueue += data;
+ };
+ Terminal.prototype.bell = function () {
+ var _this = this;
+ this.emit('bell');
+ if (this._soundBell()) {
+ this.soundManager.playBellSound();
+ }
+ if (this._visualBell()) {
+ this.element.classList.add('visual-bell-active');
+ clearTimeout(this._visualBellTimer);
+ this._visualBellTimer = window.setTimeout(function () {
+ _this.element.classList.remove('visual-bell-active');
+ }, 200);
+ }
+ };
+ Terminal.prototype.log = function (text, data) {
+ if (!this.options.debug)
+ return;
+ if (!this._context.console || !this._context.console.log)
+ return;
+ this._context.console.log(text, data);
+ };
+ Terminal.prototype.error = function (text, data) {
+ if (!this.options.debug)
+ return;
+ if (!this._context.console || !this._context.console.error)
+ return;
+ this._context.console.error(text, data);
+ };
+ Terminal.prototype.resize = function (x, y) {
+ if (isNaN(x) || isNaN(y)) {
+ return;
+ }
+ if (x === this.cols && y === this.rows) {
+ if (this.charMeasure && (!this.charMeasure.width || !this.charMeasure.height)) {
+ this.charMeasure.measure(this.options);
+ }
+ return;
+ }
+ if (x < 1)
+ x = 1;
+ if (y < 1)
+ y = 1;
+ this.buffers.resize(x, y);
+ this.cols = x;
+ this.rows = y;
+ this.buffers.setupTabStops(this.cols);
+ if (this.charMeasure) {
+ this.charMeasure.measure(this.options);
+ }
+ this.refresh(0, this.rows - 1);
+ this.emit('resize', { cols: x, rows: y });
+ };
+ Terminal.prototype.updateRange = function (y) {
+ if (y < this._refreshStart)
+ this._refreshStart = y;
+ if (y > this._refreshEnd)
+ this._refreshEnd = y;
+ };
+ Terminal.prototype.maxRange = function () {
+ this._refreshStart = 0;
+ this._refreshEnd = this.rows - 1;
+ };
+ Terminal.prototype.eraseRight = function (x, y) {
+ var line = this.buffer.lines.get(this.buffer.ybase + y);
+ if (!line) {
+ return;
+ }
+ var ch = [this.eraseAttr(), ' ', 1, 32];
+ for (; x < this.cols; x++) {
+ line[x] = ch;
+ }
+ this.updateRange(y);
+ };
+ Terminal.prototype.eraseLeft = function (x, y) {
+ var line = this.buffer.lines.get(this.buffer.ybase + y);
+ if (!line) {
+ return;
+ }
+ var ch = [this.eraseAttr(), ' ', 1, 32];
+ x++;
+ while (x--) {
+ line[x] = ch;
+ }
+ this.updateRange(y);
+ };
+ Terminal.prototype.clear = function () {
+ if (this.buffer.ybase === 0 && this.buffer.y === 0) {
+ return;
+ }
+ this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y));
+ this.buffer.lines.length = 1;
+ this.buffer.ydisp = 0;
+ this.buffer.ybase = 0;
+ this.buffer.y = 0;
+ for (var i = 1; i < this.rows; i++) {
+ this.buffer.lines.push(this.blankLine());
+ }
+ this.refresh(0, this.rows - 1);
+ this.emit('scroll', this.buffer.ydisp);
+ };
+ Terminal.prototype.eraseLine = function (y) {
+ this.eraseRight(0, y);
+ };
+ Terminal.prototype.blankLine = function (cur, isWrapped, cols) {
+ var attr = cur ? this.eraseAttr() : Buffer_1.DEFAULT_ATTR;
+ var ch = [attr, ' ', 1, 32];
+ var line = [];
+ if (isWrapped) {
+ line.isWrapped = isWrapped;
+ }
+ cols = cols || this.cols;
+ for (var i = 0; i < cols; i++) {
+ line[i] = ch;
+ }
+ return line;
+ };
+ Terminal.prototype.ch = function (cur) {
+ if (cur) {
+ return [this.eraseAttr(), ' ', 1, 32];
+ }
+ return [Buffer_1.DEFAULT_ATTR, ' ', 1, 32];
+ };
+ Terminal.prototype.is = function (term) {
+ return (this.options.termName + '').indexOf(term) === 0;
+ };
+ Terminal.prototype.handler = function (data) {
+ if (this.options.disableStdin) {
+ return;
+ }
+ if (this.selectionManager && this.selectionManager.hasSelection) {
+ this.selectionManager.clearSelection();
+ }
+ if (this.buffer.ybase !== this.buffer.ydisp) {
+ this.scrollToBottom();
+ }
+ this.emit('data', data);
+ };
+ Terminal.prototype.handleTitle = function (title) {
+ this.emit('title', title);
+ };
+ Terminal.prototype.index = function () {
+ this.buffer.y++;
+ if (this.buffer.y > this.buffer.scrollBottom) {
+ this.buffer.y--;
+ this.scroll();
+ }
+ if (this.buffer.x >= this.cols) {
+ this.buffer.x--;
+ }
+ };
+ Terminal.prototype.reverseIndex = function () {
+ if (this.buffer.y === this.buffer.scrollTop) {
+ var scrollRegionHeight = this.buffer.scrollBottom - this.buffer.scrollTop;
+ this.buffer.lines.shiftElements(this.buffer.y + this.buffer.ybase, scrollRegionHeight, 1);
+ this.buffer.lines.set(this.buffer.y + this.buffer.ybase, this.blankLine(true));
+ this.updateRange(this.buffer.scrollTop);
+ this.updateRange(this.buffer.scrollBottom);
+ }
+ else {
+ this.buffer.y--;
+ }
+ };
+ Terminal.prototype.reset = function () {
+ this.options.rows = this.rows;
+ this.options.cols = this.cols;
+ var customKeyEventHandler = this._customKeyEventHandler;
+ var inputHandler = this._inputHandler;
+ var cursorState = this.cursorState;
+ this._setup();
+ this._customKeyEventHandler = customKeyEventHandler;
+ this._inputHandler = inputHandler;
+ this.cursorState = cursorState;
+ this.refresh(0, this.rows - 1);
+ if (this.viewport) {
+ this.viewport.syncScrollArea();
+ }
+ };
+ Terminal.prototype.tabSet = function () {
+ this.buffer.tabs[this.buffer.x] = true;
+ };
+ Terminal.prototype.cancel = function (ev, force) {
+ if (!this.options.cancelEvents && !force) {
+ return;
+ }
+ ev.preventDefault();
+ ev.stopPropagation();
+ return false;
+ };
+ Terminal.prototype.matchColor = function (r1, g1, b1) {
+ var hash = (r1 << 16) | (g1 << 8) | b1;
+ if (matchColorCache[hash] != null) {
+ return matchColorCache[hash];
+ }
+ var ldiff = Infinity;
+ var li = -1;
+ var i = 0;
+ var c;
+ var r2;
+ var g2;
+ var b2;
+ var diff;
+ for (; i < ColorManager_1.DEFAULT_ANSI_COLORS.length; i++) {
+ c = ColorManager_1.DEFAULT_ANSI_COLORS[i].rgba;
+ r2 = c >>> 24;
+ g2 = c >>> 16 & 0xFF;
+ b2 = c >>> 8 & 0xFF;
+ diff = matchColorDistance(r1, g1, b1, r2, g2, b2);
+ if (diff === 0) {
+ li = i;
+ break;
+ }
+ if (diff < ldiff) {
+ ldiff = diff;
+ li = i;
+ }
+ }
+ return matchColorCache[hash] = li;
+ };
+ Terminal.prototype._visualBell = function () {
+ return false;
+ };
+ Terminal.prototype._soundBell = function () {
+ return this.options.bellStyle === 'sound';
+ };
+ return Terminal;
+}(EventEmitter_1.EventEmitter));
+exports.Terminal = Terminal;
+function wasModifierKeyOnlyEvent(ev) {
+ return ev.keyCode === 16 ||
+ ev.keyCode === 17 ||
+ ev.keyCode === 18;
+}
+var matchColorCache = {};
+function matchColorDistance(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);
+}
+
+},{"./AccessibilityManager":1,"./Buffer":2,"./BufferSet":3,"./CompositionHelper":5,"./EventEmitter":7,"./InputHandler":8,"./Linkifier":9,"./SelectionManager":10,"./SoundManager":12,"./Strings":13,"./Viewport":15,"./common/data/EscapeSequences":18,"./core/input/Keyboard":20,"./handlers/Clipboard":22,"./renderer/ColorManager":25,"./renderer/Renderer":29,"./renderer/atlas/CharAtlasCache":33,"./renderer/dom/DomRenderer":40,"./shared/utils/Browser":44,"./ui/CharMeasure":45,"./ui/Lifecycle":46,"./ui/MouseZoneManager":47,"./ui/ScreenDprMonitor":49,"./utils/Clone":50,"./utils/MouseHelper":51}],15:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Lifecycle_1 = require("./common/Lifecycle");
+var Lifecycle_2 = require("./ui/Lifecycle");
+var FALLBACK_SCROLL_BAR_WIDTH = 15;
+var Viewport = (function (_super) {
+ __extends(Viewport, _super);
+ function Viewport(_terminal, _viewportElement, _scrollArea, _charMeasure) {
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._viewportElement = _viewportElement;
+ _this._scrollArea = _scrollArea;
+ _this._charMeasure = _charMeasure;
+ _this.scrollBarWidth = 0;
+ _this._currentRowHeight = 0;
+ _this._lastRecordedBufferLength = 0;
+ _this._lastRecordedViewportHeight = 0;
+ _this._lastRecordedBufferHeight = 0;
+ _this._wheelPartialScroll = 0;
+ _this.scrollBarWidth = (_this._viewportElement.offsetWidth - _this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH;
+ _this.register(Lifecycle_2.addDisposableDomListener(_this._viewportElement, 'scroll', _this._onScroll.bind(_this)));
+ setTimeout(function () { return _this.syncScrollArea(); }, 0);
+ return _this;
+ }
+ Viewport.prototype.onThemeChanged = function (colors) {
+ this._viewportElement.style.backgroundColor = colors.background.css;
+ };
+ Viewport.prototype._refresh = function () {
+ if (this._charMeasure.height > 0) {
+ this._currentRowHeight = this._terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio;
+ this._lastRecordedViewportHeight = this._viewportElement.offsetHeight;
+ var newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._terminal.renderer.dimensions.canvasHeight);
+ if (this._lastRecordedBufferHeight !== newBufferHeight) {
+ this._lastRecordedBufferHeight = newBufferHeight;
+ this._scrollArea.style.height = this._lastRecordedBufferHeight + 'px';
+ }
+ }
+ };
+ Viewport.prototype.syncScrollArea = function () {
+ if (this._lastRecordedBufferLength !== this._terminal.buffer.lines.length) {
+ this._lastRecordedBufferLength = this._terminal.buffer.lines.length;
+ this._refresh();
+ }
+ else if (this._lastRecordedViewportHeight !== this._terminal.renderer.dimensions.canvasHeight) {
+ this._refresh();
+ }
+ else {
+ if (this._terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) {
+ this._refresh();
+ }
+ }
+ var scrollTop = this._terminal.buffer.ydisp * this._currentRowHeight;
+ if (this._viewportElement.scrollTop !== scrollTop) {
+ this._viewportElement.scrollTop = scrollTop;
+ }
+ };
+ Viewport.prototype._onScroll = function (ev) {
+ if (!this._viewportElement.offsetParent) {
+ return;
+ }
+ var newRow = Math.round(this._viewportElement.scrollTop / this._currentRowHeight);
+ var diff = newRow - this._terminal.buffer.ydisp;
+ this._terminal.scrollLines(diff, true);
+ };
+ Viewport.prototype.onWheel = function (ev) {
+ var amount = this._getPixelsScrolled(ev);
+ if (amount === 0) {
+ return;
+ }
+ this._viewportElement.scrollTop += amount;
+ ev.preventDefault();
+ };
+ Viewport.prototype._getPixelsScrolled = function (ev) {
+ if (ev.deltaY === 0) {
+ return 0;
+ }
+ var amount = ev.deltaY;
+ if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) {
+ amount *= this._currentRowHeight;
+ }
+ else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
+ amount *= this._currentRowHeight * this._terminal.rows;
+ }
+ return amount;
+ };
+ Viewport.prototype.getLinesScrolled = function (ev) {
+ if (ev.deltaY === 0) {
+ return 0;
+ }
+ var amount = ev.deltaY;
+ if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
+ amount /= this._currentRowHeight + 0.0;
+ this._wheelPartialScroll += amount;
+ amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1);
+ this._wheelPartialScroll %= 1;
+ }
+ else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
+ amount *= this._terminal.rows;
+ }
+ return amount;
+ };
+ Viewport.prototype.onTouchStart = function (ev) {
+ this._lastTouchY = ev.touches[0].pageY;
+ };
+ Viewport.prototype.onTouchMove = function (ev) {
+ var deltaY = this._lastTouchY - ev.touches[0].pageY;
+ this._lastTouchY = ev.touches[0].pageY;
+ if (deltaY === 0) {
+ return;
+ }
+ this._viewportElement.scrollTop += deltaY;
+ ev.preventDefault();
+ };
+ return Viewport;
+}(Lifecycle_1.Disposable));
+exports.Viewport = Viewport;
+
+},{"./common/Lifecycle":17,"./ui/Lifecycle":46}],16:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventEmitter_1 = require("../EventEmitter");
+var CircularList = (function (_super) {
+ __extends(CircularList, _super);
+ function CircularList(_maxLength) {
+ var _this = _super.call(this) || this;
+ _this._maxLength = _maxLength;
+ _this._array = new Array(_this._maxLength);
+ _this._startIndex = 0;
+ _this._length = 0;
+ return _this;
+ }
+ Object.defineProperty(CircularList.prototype, "maxLength", {
+ get: function () {
+ return this._maxLength;
+ },
+ set: function (newMaxLength) {
+ if (this._maxLength === newMaxLength) {
+ return;
+ }
+ var newArray = new Array(newMaxLength);
+ for (var i = 0; i < Math.min(newMaxLength, this.length); i++) {
+ newArray[i] = this._array[this._getCyclicIndex(i)];
+ }
+ this._array = newArray;
+ this._maxLength = newMaxLength;
+ this._startIndex = 0;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(CircularList.prototype, "length", {
+ get: function () {
+ return this._length;
+ },
+ set: function (newLength) {
+ if (newLength > this._length) {
+ for (var i = this._length; i < newLength; i++) {
+ this._array[i] = undefined;
+ }
+ }
+ this._length = newLength;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ CircularList.prototype.get = function (index) {
+ return this._array[this._getCyclicIndex(index)];
+ };
+ CircularList.prototype.set = function (index, value) {
+ this._array[this._getCyclicIndex(index)] = value;
+ };
+ CircularList.prototype.push = function (value) {
+ this._array[this._getCyclicIndex(this._length)] = value;
+ if (this._length === this._maxLength) {
+ this._startIndex++;
+ if (this._startIndex === this._maxLength) {
+ this._startIndex = 0;
+ }
+ this.emit('trim', 1);
+ }
+ else {
+ this._length++;
+ }
+ };
+ CircularList.prototype.pop = function () {
+ return this._array[this._getCyclicIndex(this._length-- - 1)];
+ };
+ CircularList.prototype.splice = function (start, deleteCount) {
+ var items = [];
+ for (var _i = 2; _i < arguments.length; _i++) {
+ items[_i - 2] = arguments[_i];
+ }
+ if (deleteCount) {
+ for (var i = start; i < this._length - deleteCount; i++) {
+ this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)];
+ }
+ this._length -= deleteCount;
+ }
+ if (items && items.length) {
+ for (var i = this._length - 1; i >= start; i--) {
+ this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)];
+ }
+ for (var i = 0; i < items.length; i++) {
+ this._array[this._getCyclicIndex(start + i)] = items[i];
+ }
+ if (this._length + items.length > this.maxLength) {
+ var countToTrim = (this._length + items.length) - this.maxLength;
+ this._startIndex += countToTrim;
+ this._length = this.maxLength;
+ this.emit('trim', countToTrim);
+ }
+ else {
+ this._length += items.length;
+ }
+ }
+ };
+ CircularList.prototype.trimStart = function (count) {
+ if (count > this._length) {
+ count = this._length;
+ }
+ this._startIndex += count;
+ this._length -= count;
+ this.emit('trim', count);
+ };
+ CircularList.prototype.shiftElements = function (start, count, offset) {
+ if (count <= 0) {
+ return;
+ }
+ if (start < 0 || start >= this._length) {
+ throw new Error('start argument out of range');
+ }
+ if (start + offset < 0) {
+ throw new Error('Cannot shift elements in list beyond index 0');
+ }
+ if (offset > 0) {
+ for (var i = count - 1; i >= 0; i--) {
+ this.set(start + i + offset, this.get(start + i));
+ }
+ var expandListBy = (start + count + offset) - this._length;
+ if (expandListBy > 0) {
+ this._length += expandListBy;
+ while (this._length > this.maxLength) {
+ this._length--;
+ this._startIndex++;
+ this.emit('trim', 1);
+ }
+ }
+ }
+ else {
+ for (var i = 0; i < count; i++) {
+ this.set(start + i + offset, this.get(start + i));
+ }
+ }
+ };
+ CircularList.prototype._getCyclicIndex = function (index) {
+ return (this._startIndex + index) % this.maxLength;
+ };
+ return CircularList;
+}(EventEmitter_1.EventEmitter));
+exports.CircularList = CircularList;
+
+},{"../EventEmitter":7}],17:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Disposable = (function () {
+ function Disposable() {
+ this._disposables = [];
+ }
+ Disposable.prototype.dispose = function () {
+ this._disposables.forEach(function (d) { return d.dispose(); });
+ this._disposables.length = 0;
+ };
+ Disposable.prototype.register = function (d) {
+ this._disposables.push(d);
+ };
+ return Disposable;
+}());
+exports.Disposable = Disposable;
+
+},{}],18:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var C0;
+(function (C0) {
+ C0.NUL = '\x00';
+ C0.SOH = '\x01';
+ C0.STX = '\x02';
+ C0.ETX = '\x03';
+ C0.EOT = '\x04';
+ C0.ENQ = '\x05';
+ C0.ACK = '\x06';
+ C0.BEL = '\x07';
+ C0.BS = '\x08';
+ C0.HT = '\x09';
+ C0.LF = '\x0a';
+ C0.VT = '\x0b';
+ C0.FF = '\x0c';
+ C0.CR = '\x0d';
+ C0.SO = '\x0e';
+ C0.SI = '\x0f';
+ C0.DLE = '\x10';
+ C0.DC1 = '\x11';
+ C0.DC2 = '\x12';
+ C0.DC3 = '\x13';
+ C0.DC4 = '\x14';
+ C0.NAK = '\x15';
+ C0.SYN = '\x16';
+ C0.ETB = '\x17';
+ C0.CAN = '\x18';
+ C0.EM = '\x19';
+ C0.SUB = '\x1a';
+ C0.ESC = '\x1b';
+ C0.FS = '\x1c';
+ C0.GS = '\x1d';
+ C0.RS = '\x1e';
+ C0.US = '\x1f';
+ C0.SP = '\x20';
+ C0.DEL = '\x7f';
+})(C0 = exports.C0 || (exports.C0 = {}));
+var C1;
+(function (C1) {
+ C1.PAD = '\x80';
+ C1.HOP = '\x81';
+ C1.BPH = '\x82';
+ C1.NBH = '\x83';
+ C1.IND = '\x84';
+ C1.NEL = '\x85';
+ C1.SSA = '\x86';
+ C1.ESA = '\x87';
+ C1.HTS = '\x88';
+ C1.HTJ = '\x89';
+ C1.VTS = '\x8a';
+ C1.PLD = '\x8b';
+ C1.PLU = '\x8c';
+ C1.RI = '\x8d';
+ C1.SS2 = '\x8e';
+ C1.SS3 = '\x8f';
+ C1.DCS = '\x90';
+ C1.PU1 = '\x91';
+ C1.PU2 = '\x92';
+ C1.STS = '\x93';
+ C1.CCH = '\x94';
+ C1.MW = '\x95';
+ C1.SPA = '\x96';
+ C1.EPA = '\x97';
+ C1.SOS = '\x98';
+ C1.SGCI = '\x99';
+ C1.SCI = '\x9a';
+ C1.CSI = '\x9b';
+ C1.ST = '\x9c';
+ C1.OSC = '\x9d';
+ C1.PM = '\x9e';
+ C1.APC = '\x9f';
+})(C1 = exports.C1 || (exports.C1 = {}));
+
+},{}],19:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CHARSETS = {};
@@ -324,4175 +5093,84 @@ exports.CHARSETS['='] = {
'~': 'û'
};
-
-
-},{}],4:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var CompositionHelper = (function () {
- function CompositionHelper(textarea, compositionView, terminal) {
- this.textarea = textarea;
- this.compositionView = compositionView;
- this.terminal = terminal;
- this.isComposing = false;
- this.isSendingComposition = false;
- this.compositionPosition = { start: null, end: null };
- }
- CompositionHelper.prototype.compositionstart = function () {
- this.isComposing = true;
- this.compositionPosition.start = this.textarea.value.length;
- this.compositionView.textContent = '';
- this.compositionView.classList.add('active');
- };
- CompositionHelper.prototype.compositionupdate = function (ev) {
- var _this = this;
- this.compositionView.textContent = ev.data;
- this.updateCompositionElements();
- setTimeout(function () {
- _this.compositionPosition.end = _this.textarea.value.length;
- }, 0);
- };
- CompositionHelper.prototype.compositionend = function () {
- this.finalizeComposition(true);
- };
- CompositionHelper.prototype.keydown = function (ev) {
- if (this.isComposing || this.isSendingComposition) {
- if (ev.keyCode === 229) {
- return false;
- }
- else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) {
- return false;
- }
- else {
- this.finalizeComposition(false);
- }
- }
- if (ev.keyCode === 229) {
- this.handleAnyTextareaChanges();
- return false;
- }
- return true;
- };
- CompositionHelper.prototype.finalizeComposition = function (waitForPropogation) {
- var _this = this;
- this.compositionView.classList.remove('active');
- this.isComposing = false;
- this.clearTextareaPosition();
- if (!waitForPropogation) {
- this.isSendingComposition = false;
- var input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end);
- this.terminal.handler(input);
- }
- else {
- var currentCompositionPosition_1 = {
- start: this.compositionPosition.start,
- end: this.compositionPosition.end,
- };
- this.isSendingComposition = true;
- setTimeout(function () {
- if (_this.isSendingComposition) {
- _this.isSendingComposition = false;
- var input = void 0;
- if (_this.isComposing) {
- input = _this.textarea.value.substring(currentCompositionPosition_1.start, currentCompositionPosition_1.end);
- }
- else {
- input = _this.textarea.value.substring(currentCompositionPosition_1.start);
- }
- _this.terminal.handler(input);
- }
- }, 0);
- }
- };
- CompositionHelper.prototype.handleAnyTextareaChanges = function () {
- var _this = this;
- var oldValue = this.textarea.value;
- setTimeout(function () {
- if (!_this.isComposing) {
- var newValue = _this.textarea.value;
- var diff = newValue.replace(oldValue, '');
- if (diff.length > 0) {
- _this.terminal.handler(diff);
- }
- }
- }, 0);
- };
- CompositionHelper.prototype.updateCompositionElements = function (dontRecurse) {
- var _this = this;
- if (!this.isComposing) {
- return;
- }
- var cursor = this.terminal.element.querySelector('.terminal-cursor');
- if (cursor) {
- var xtermRows = this.terminal.element.querySelector('.xterm-rows');
- var cursorTop = xtermRows.offsetTop + cursor.offsetTop;
- this.compositionView.style.left = cursor.offsetLeft + 'px';
- this.compositionView.style.top = cursorTop + 'px';
- this.compositionView.style.height = cursor.offsetHeight + 'px';
- this.compositionView.style.lineHeight = cursor.offsetHeight + 'px';
- var compositionViewBounds = this.compositionView.getBoundingClientRect();
- this.textarea.style.left = cursor.offsetLeft + 'px';
- this.textarea.style.top = cursorTop + 'px';
- this.textarea.style.width = compositionViewBounds.width + 'px';
- this.textarea.style.height = compositionViewBounds.height + 'px';
- this.textarea.style.lineHeight = compositionViewBounds.height + 'px';
- }
- if (!dontRecurse) {
- setTimeout(function () { return _this.updateCompositionElements(true); }, 0);
- }
- };
- ;
- CompositionHelper.prototype.clearTextareaPosition = function () {
- this.textarea.style.left = '';
- this.textarea.style.top = '';
- };
- ;
- return CompositionHelper;
-}());
-exports.CompositionHelper = CompositionHelper;
-
-
-
-},{}],5:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var C0;
-(function (C0) {
- C0.NUL = '\x00';
- C0.SOH = '\x01';
- C0.STX = '\x02';
- C0.ETX = '\x03';
- C0.EOT = '\x04';
- C0.ENQ = '\x05';
- C0.ACK = '\x06';
- C0.BEL = '\x07';
- C0.BS = '\x08';
- C0.HT = '\x09';
- C0.LF = '\x0a';
- C0.VT = '\x0b';
- C0.FF = '\x0c';
- C0.CR = '\x0d';
- C0.SO = '\x0e';
- C0.SI = '\x0f';
- C0.DLE = '\x10';
- C0.DC1 = '\x11';
- C0.DC2 = '\x12';
- C0.DC3 = '\x13';
- C0.DC4 = '\x14';
- C0.NAK = '\x15';
- C0.SYN = '\x16';
- C0.ETB = '\x17';
- C0.CAN = '\x18';
- C0.EM = '\x19';
- C0.SUB = '\x1a';
- C0.ESC = '\x1b';
- C0.FS = '\x1c';
- C0.GS = '\x1d';
- C0.RS = '\x1e';
- C0.US = '\x1f';
- C0.SP = '\x20';
- C0.DEL = '\x7f';
-})(C0 = exports.C0 || (exports.C0 = {}));
-;
-
-
-
-},{}],6:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-;
-var EventEmitter = (function () {
- function EventEmitter() {
- this._events = this._events || {};
- }
- EventEmitter.prototype.on = function (type, listener) {
- this._events[type] = this._events[type] || [];
- this._events[type].push(listener);
- };
- EventEmitter.prototype.off = function (type, listener) {
- if (!this._events[type]) {
- return;
- }
- var obj = this._events[type];
- var i = obj.length;
- while (i--) {
- if (obj[i] === listener || obj[i].listener === listener) {
- obj.splice(i, 1);
- return;
- }
- }
- };
- EventEmitter.prototype.removeAllListeners = function (type) {
- if (this._events[type]) {
- delete this._events[type];
- }
- };
- EventEmitter.prototype.once = function (type, listener) {
- function on() {
- var args = Array.prototype.slice.call(arguments);
- this.off(type, on);
- return listener.apply(this, args);
- }
- on.listener = listener;
- return this.on(type, on);
- };
- EventEmitter.prototype.emit = function (type) {
- var args = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- args[_i - 1] = arguments[_i];
- }
- if (!this._events[type]) {
- return;
- }
- var obj = this._events[type];
- for (var i = 0; i < obj.length; i++) {
- obj[i].apply(this, args);
- }
- };
- EventEmitter.prototype.listeners = function (type) {
- return this._events[type] || [];
- };
- return EventEmitter;
-}());
-exports.EventEmitter = EventEmitter;
-
-
-
-},{}],7:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var EscapeSequences_1 = require("./EscapeSequences");
-var Charsets_1 = require("./Charsets");
-var InputHandler = (function () {
- function InputHandler(_terminal) {
- this._terminal = _terminal;
- }
- InputHandler.prototype.addChar = function (char, code) {
- if (char >= ' ') {
- var ch_width = exports.wcwidth(code);
- if (this._terminal.charset && this._terminal.charset[char]) {
- char = this._terminal.charset[char];
- }
- var row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- if (!ch_width && this._terminal.buffer.x) {
- if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1]) {
- if (!this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][2]) {
- if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2])
- this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][1] += char;
- }
- else {
- this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][1] += char;
- }
- this._terminal.updateRange(this._terminal.buffer.y);
- }
- return;
- }
- if (this._terminal.buffer.x + ch_width - 1 >= this._terminal.cols) {
- if (this._terminal.wraparoundMode) {
- this._terminal.buffer.x = 0;
- this._terminal.buffer.y++;
- if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) {
- this._terminal.buffer.y--;
- this._terminal.scroll(true);
- }
- else {
- this._terminal.buffer.lines.get(this._terminal.buffer.y).isWrapped = true;
- }
- }
- else {
- if (ch_width === 2)
- return;
- }
- }
- row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- if (this._terminal.insertMode) {
- for (var moves = 0; moves < ch_width; ++moves) {
- var removed = this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).pop();
- if (removed[2] === 0
- && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2]
- && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2][2] === 2) {
- this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1];
- }
- this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 0, [this._terminal.curAttr, ' ', 1]);
- }
- }
- this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, ch_width];
- this._terminal.buffer.x++;
- this._terminal.updateRange(this._terminal.buffer.y);
- if (ch_width === 2) {
- this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0];
- this._terminal.buffer.x++;
- }
- }
- };
- InputHandler.prototype.bell = function () {
- var _this = this;
- if (!this._terminal.visualBell) {
- return;
- }
- this._terminal.element.style.borderColor = 'white';
- setTimeout(function () { return _this._terminal.element.style.borderColor = ''; }, 10);
- if (this._terminal.popOnBell) {
- this._terminal.focus();
- }
- };
- InputHandler.prototype.lineFeed = function () {
- if (this._terminal.convertEol) {
- this._terminal.buffer.x = 0;
- }
- this._terminal.buffer.y++;
- if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) {
- this._terminal.buffer.y--;
- this._terminal.scroll();
- }
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x--;
- }
- this._terminal.emit('lineFeed');
- };
- InputHandler.prototype.carriageReturn = function () {
- this._terminal.buffer.x = 0;
- };
- InputHandler.prototype.backspace = function () {
- if (this._terminal.buffer.x > 0) {
- this._terminal.buffer.x--;
- }
- };
- InputHandler.prototype.tab = function () {
- this._terminal.buffer.x = this._terminal.nextStop();
- };
- InputHandler.prototype.shiftOut = function () {
- this._terminal.setgLevel(1);
- };
- InputHandler.prototype.shiftIn = function () {
- this._terminal.setgLevel(0);
- };
- InputHandler.prototype.insertChars = function (params) {
- var param, row, j, ch;
- param = params[0];
- if (param < 1)
- param = 1;
- row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- j = this._terminal.buffer.x;
- ch = [this._terminal.eraseAttr(), ' ', 1];
- while (param-- && j < this._terminal.cols) {
- this._terminal.buffer.lines.get(row).splice(j++, 0, ch);
- this._terminal.buffer.lines.get(row).pop();
- }
- };
- InputHandler.prototype.cursorUp = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.y -= param;
- if (this._terminal.buffer.y < 0) {
- this._terminal.buffer.y = 0;
- }
- };
- InputHandler.prototype.cursorDown = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.y += param;
- if (this._terminal.buffer.y >= this._terminal.rows) {
- this._terminal.buffer.y = this._terminal.rows - 1;
- }
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x--;
- }
- };
- InputHandler.prototype.cursorForward = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.x += param;
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x = this._terminal.cols - 1;
- }
- };
- InputHandler.prototype.cursorBackward = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x--;
- }
- this._terminal.buffer.x -= param;
- if (this._terminal.buffer.x < 0) {
- this._terminal.buffer.x = 0;
- }
- };
- InputHandler.prototype.cursorNextLine = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.y += param;
- if (this._terminal.buffer.y >= this._terminal.rows) {
- this._terminal.buffer.y = this._terminal.rows - 1;
- }
- this._terminal.buffer.x = 0;
- };
- InputHandler.prototype.cursorPrecedingLine = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.y -= param;
- if (this._terminal.buffer.y < 0) {
- this._terminal.buffer.y = 0;
- }
- this._terminal.buffer.x = 0;
- };
- InputHandler.prototype.cursorCharAbsolute = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.x = param - 1;
- };
- InputHandler.prototype.cursorPosition = function (params) {
- var row, col;
- row = params[0] - 1;
- if (params.length >= 2) {
- col = params[1] - 1;
- }
- else {
- col = 0;
- }
- if (row < 0) {
- row = 0;
- }
- else if (row >= this._terminal.rows) {
- row = this._terminal.rows - 1;
- }
- if (col < 0) {
- col = 0;
- }
- else if (col >= this._terminal.cols) {
- col = this._terminal.cols - 1;
- }
- this._terminal.buffer.x = col;
- this._terminal.buffer.y = row;
- };
- InputHandler.prototype.cursorForwardTab = function (params) {
- var param = params[0] || 1;
- while (param--) {
- this._terminal.buffer.x = this._terminal.nextStop();
- }
- };
- InputHandler.prototype.eraseInDisplay = function (params) {
- var j;
- switch (params[0]) {
- case 0:
- this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y);
- j = this._terminal.buffer.y + 1;
- for (; j < this._terminal.rows; j++) {
- this._terminal.eraseLine(j);
- }
- break;
- case 1:
- this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y);
- j = this._terminal.buffer.y;
- while (j--) {
- this._terminal.eraseLine(j);
- }
- break;
- case 2:
- j = this._terminal.rows;
- while (j--)
- this._terminal.eraseLine(j);
- break;
- case 3:
- var scrollBackSize = this._terminal.buffer.lines.length - this._terminal.rows;
- if (scrollBackSize > 0) {
- this._terminal.buffer.lines.trimStart(scrollBackSize);
- this._terminal.buffer.ybase = Math.max(this._terminal.buffer.ybase - scrollBackSize, 0);
- this._terminal.buffer.ydisp = Math.max(this._terminal.buffer.ydisp - scrollBackSize, 0);
- this._terminal.emit('scroll', 0);
- }
- break;
- }
- };
- InputHandler.prototype.eraseInLine = function (params) {
- switch (params[0]) {
- case 0:
- this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y);
- break;
- case 1:
- this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y);
- break;
- case 2:
- this._terminal.eraseLine(this._terminal.buffer.y);
- break;
- }
- };
- InputHandler.prototype.insertLines = function (params) {
- var param, row, j;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
- j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j + 1;
- while (param--) {
- if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) {
- this._terminal.buffer.lines.trimStart(1);
- this._terminal.buffer.ybase--;
- this._terminal.buffer.ydisp--;
- row--;
- j--;
- }
- this._terminal.buffer.lines.splice(row, 0, this._terminal.blankLine(true));
- this._terminal.buffer.lines.splice(j, 1);
- }
- this._terminal.updateRange(this._terminal.buffer.y);
- this._terminal.updateRange(this._terminal.buffer.scrollBottom);
- };
- InputHandler.prototype.deleteLines = function (params) {
- var param, row, j;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
- j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j;
- while (param--) {
- if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) {
- this._terminal.buffer.lines.trimStart(1);
- this._terminal.buffer.ybase -= 1;
- this._terminal.buffer.ydisp -= 1;
- }
- this._terminal.buffer.lines.splice(j + 1, 0, this._terminal.blankLine(true));
- this._terminal.buffer.lines.splice(row, 1);
- }
- this._terminal.updateRange(this._terminal.buffer.y);
- this._terminal.updateRange(this._terminal.buffer.scrollBottom);
- };
- InputHandler.prototype.deleteChars = function (params) {
- var param, row, ch;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- ch = [this._terminal.eraseAttr(), ' ', 1];
- while (param--) {
- this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 1);
- this._terminal.buffer.lines.get(row).push(ch);
- }
- };
- InputHandler.prototype.scrollUp = function (params) {
- var param = params[0] || 1;
- while (param--) {
- this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 1);
- this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 0, this._terminal.blankLine());
- }
- this._terminal.updateRange(this._terminal.buffer.scrollTop);
- this._terminal.updateRange(this._terminal.buffer.scrollBottom);
- };
- InputHandler.prototype.scrollDown = function (params) {
- var param = params[0] || 1;
- while (param--) {
- this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 1);
- this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 0, this._terminal.blankLine());
- }
- this._terminal.updateRange(this._terminal.buffer.scrollTop);
- this._terminal.updateRange(this._terminal.buffer.scrollBottom);
- };
- InputHandler.prototype.eraseChars = function (params) {
- var param, row, j, ch;
- param = params[0];
- if (param < 1) {
- param = 1;
- }
- row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- j = this._terminal.buffer.x;
- ch = [this._terminal.eraseAttr(), ' ', 1];
- while (param-- && j < this._terminal.cols) {
- this._terminal.buffer.lines.get(row)[j++] = ch;
- }
- };
- InputHandler.prototype.cursorBackwardTab = function (params) {
- var param = params[0] || 1;
- while (param--) {
- this._terminal.buffer.x = this._terminal.prevStop();
- }
- };
- InputHandler.prototype.charPosAbsolute = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.x = param - 1;
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x = this._terminal.cols - 1;
- }
- };
- InputHandler.prototype.HPositionRelative = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.x += param;
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x = this._terminal.cols - 1;
- }
- };
- InputHandler.prototype.repeatPrecedingCharacter = function (params) {
- var param = params[0] || 1, line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + this._terminal.buffer.y), ch = line[this._terminal.buffer.x - 1] || [this._terminal.defAttr, ' ', 1];
- while (param--) {
- line[this._terminal.buffer.x++] = ch;
- }
- };
- InputHandler.prototype.sendDeviceAttributes = function (params) {
- if (params[0] > 0) {
- return;
- }
- if (!this._terminal.prefix) {
- if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) {
- this._terminal.send(EscapeSequences_1.C0.ESC + '[?1;2c');
- }
- else if (this._terminal.is('linux')) {
- this._terminal.send(EscapeSequences_1.C0.ESC + '[?6c');
- }
- }
- else if (this._terminal.prefix === '>') {
- if (this._terminal.is('xterm')) {
- this._terminal.send(EscapeSequences_1.C0.ESC + '[>0;276;0c');
- }
- else if (this._terminal.is('rxvt-unicode')) {
- this._terminal.send(EscapeSequences_1.C0.ESC + '[>85;95;0c');
- }
- else if (this._terminal.is('linux')) {
- this._terminal.send(params[0] + 'c');
- }
- else if (this._terminal.is('screen')) {
- this._terminal.send(EscapeSequences_1.C0.ESC + '[>83;40003;0c');
- }
- }
- };
- InputHandler.prototype.linePosAbsolute = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.y = param - 1;
- if (this._terminal.buffer.y >= this._terminal.rows) {
- this._terminal.buffer.y = this._terminal.rows - 1;
- }
- };
- InputHandler.prototype.VPositionRelative = function (params) {
- var param = params[0];
- if (param < 1) {
- param = 1;
- }
- this._terminal.buffer.y += param;
- if (this._terminal.buffer.y >= this._terminal.rows) {
- this._terminal.buffer.y = this._terminal.rows - 1;
- }
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x--;
- }
- };
- InputHandler.prototype.HVPosition = function (params) {
- if (params[0] < 1)
- params[0] = 1;
- if (params[1] < 1)
- params[1] = 1;
- this._terminal.buffer.y = params[0] - 1;
- if (this._terminal.buffer.y >= this._terminal.rows) {
- this._terminal.buffer.y = this._terminal.rows - 1;
- }
- this._terminal.buffer.x = params[1] - 1;
- if (this._terminal.buffer.x >= this._terminal.cols) {
- this._terminal.buffer.x = this._terminal.cols - 1;
- }
- };
- InputHandler.prototype.tabClear = function (params) {
- var param = params[0];
- if (param <= 0) {
- delete this._terminal.buffer.tabs[this._terminal.buffer.x];
- }
- else if (param === 3) {
- this._terminal.buffer.tabs = {};
- }
- };
- InputHandler.prototype.setMode = function (params) {
- if (params.length > 1) {
- for (var i = 0; i < params.length; i++) {
- this.setMode([params[i]]);
- }
- return;
- }
- if (!this._terminal.prefix) {
- switch (params[0]) {
- case 4:
- this._terminal.insertMode = true;
- break;
- case 20:
- break;
- }
- }
- else if (this._terminal.prefix === '?') {
- switch (params[0]) {
- case 1:
- this._terminal.applicationCursor = true;
- break;
- case 2:
- this._terminal.setgCharset(0, Charsets_1.DEFAULT_CHARSET);
- this._terminal.setgCharset(1, Charsets_1.DEFAULT_CHARSET);
- this._terminal.setgCharset(2, Charsets_1.DEFAULT_CHARSET);
- this._terminal.setgCharset(3, Charsets_1.DEFAULT_CHARSET);
- break;
- case 3:
- this._terminal.savedCols = this._terminal.cols;
- this._terminal.resize(132, this._terminal.rows);
- break;
- case 6:
- this._terminal.originMode = true;
- break;
- case 7:
- this._terminal.wraparoundMode = true;
- break;
- case 12:
- break;
- case 66:
- this._terminal.log('Serial port requested application keypad.');
- this._terminal.applicationKeypad = true;
- this._terminal.viewport.syncScrollArea();
- break;
- case 9:
- case 1000:
- case 1002:
- case 1003:
- this._terminal.x10Mouse = params[0] === 9;
- this._terminal.vt200Mouse = params[0] === 1000;
- this._terminal.normalMouse = params[0] > 1000;
- this._terminal.mouseEvents = true;
- this._terminal.element.classList.add('enable-mouse-events');
- this._terminal.selectionManager.disable();
- this._terminal.log('Binding to mouse events.');
- break;
- case 1004:
- this._terminal.sendFocus = true;
- break;
- case 1005:
- this._terminal.utfMouse = true;
- break;
- case 1006:
- this._terminal.sgrMouse = true;
- break;
- case 1015:
- this._terminal.urxvtMouse = true;
- break;
- case 25:
- this._terminal.cursorHidden = false;
- break;
- case 1049:
- case 47:
- case 1047:
- this._terminal.buffers.activateAltBuffer();
- this._terminal.viewport.syncScrollArea();
- this._terminal.showCursor();
- break;
- }
- }
- };
- InputHandler.prototype.resetMode = function (params) {
- if (params.length > 1) {
- for (var i = 0; i < params.length; i++) {
- this.resetMode([params[i]]);
- }
- return;
- }
- if (!this._terminal.prefix) {
- switch (params[0]) {
- case 4:
- this._terminal.insertMode = false;
- break;
- case 20:
- break;
- }
- }
- else if (this._terminal.prefix === '?') {
- switch (params[0]) {
- case 1:
- this._terminal.applicationCursor = false;
- break;
- case 3:
- if (this._terminal.cols === 132 && this._terminal.savedCols) {
- this._terminal.resize(this._terminal.savedCols, this._terminal.rows);
- }
- delete this._terminal.savedCols;
- break;
- case 6:
- this._terminal.originMode = false;
- break;
- case 7:
- this._terminal.wraparoundMode = false;
- break;
- case 12:
- break;
- case 66:
- this._terminal.log('Switching back to normal keypad.');
- this._terminal.applicationKeypad = false;
- this._terminal.viewport.syncScrollArea();
- break;
- case 9:
- case 1000:
- case 1002:
- case 1003:
- this._terminal.x10Mouse = false;
- this._terminal.vt200Mouse = false;
- this._terminal.normalMouse = false;
- this._terminal.mouseEvents = false;
- this._terminal.element.classList.remove('enable-mouse-events');
- this._terminal.selectionManager.enable();
- break;
- case 1004:
- this._terminal.sendFocus = false;
- break;
- case 1005:
- this._terminal.utfMouse = false;
- break;
- case 1006:
- this._terminal.sgrMouse = false;
- break;
- case 1015:
- this._terminal.urxvtMouse = false;
- break;
- case 25:
- this._terminal.cursorHidden = true;
- break;
- case 1049:
- case 47:
- case 1047:
- this._terminal.buffers.activateNormalBuffer();
- this._terminal.selectionManager.setBuffer(this._terminal.buffer.lines);
- this._terminal.refresh(0, this._terminal.rows - 1);
- this._terminal.viewport.syncScrollArea();
- this._terminal.showCursor();
- break;
- }
- }
- };
- InputHandler.prototype.charAttributes = function (params) {
- if (params.length === 1 && params[0] === 0) {
- this._terminal.curAttr = this._terminal.defAttr;
- return;
- }
- var l = params.length, i = 0, flags = this._terminal.curAttr >> 18, fg = (this._terminal.curAttr >> 9) & 0x1ff, bg = this._terminal.curAttr & 0x1ff, p;
- for (; i < l; i++) {
- p = params[i];
- if (p >= 30 && p <= 37) {
- fg = p - 30;
- }
- else if (p >= 40 && p <= 47) {
- bg = p - 40;
- }
- else if (p >= 90 && p <= 97) {
- p += 8;
- fg = p - 90;
- }
- else if (p >= 100 && p <= 107) {
- p += 8;
- bg = p - 100;
- }
- else if (p === 0) {
- flags = this._terminal.defAttr >> 18;
- fg = (this._terminal.defAttr >> 9) & 0x1ff;
- bg = this._terminal.defAttr & 0x1ff;
- }
- else if (p === 1) {
- flags |= 1;
- }
- else if (p === 4) {
- flags |= 2;
- }
- else if (p === 5) {
- flags |= 4;
- }
- else if (p === 7) {
- flags |= 8;
- }
- else if (p === 8) {
- flags |= 16;
- }
- else if (p === 22) {
- flags &= ~1;
- }
- else if (p === 24) {
- flags &= ~2;
- }
- else if (p === 25) {
- flags &= ~4;
- }
- else if (p === 27) {
- flags &= ~8;
- }
- else if (p === 28) {
- flags &= ~16;
- }
- else if (p === 39) {
- fg = (this._terminal.defAttr >> 9) & 0x1ff;
- }
- else if (p === 49) {
- bg = this._terminal.defAttr & 0x1ff;
- }
- else if (p === 38) {
- if (params[i + 1] === 2) {
- i += 2;
- fg = this._terminal.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;
- p = params[i] & 0xff;
- fg = p;
- }
- }
- else if (p === 48) {
- if (params[i + 1] === 2) {
- i += 2;
- bg = this._terminal.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;
- p = params[i] & 0xff;
- bg = p;
- }
- }
- else if (p === 100) {
- fg = (this._terminal.defAttr >> 9) & 0x1ff;
- bg = this._terminal.defAttr & 0x1ff;
- }
- else {
- this._terminal.error('Unknown SGR attribute: %d.', p);
- }
- }
- this._terminal.curAttr = (flags << 18) | (fg << 9) | bg;
- };
- InputHandler.prototype.deviceStatus = function (params) {
- if (!this._terminal.prefix) {
- switch (params[0]) {
- case 5:
- this._terminal.send(EscapeSequences_1.C0.ESC + '[0n');
- break;
- case 6:
- this._terminal.send(EscapeSequences_1.C0.ESC + '['
- + (this._terminal.buffer.y + 1)
- + ';'
- + (this._terminal.buffer.x + 1)
- + 'R');
- break;
- }
- }
- else if (this._terminal.prefix === '?') {
- switch (params[0]) {
- case 6:
- this._terminal.send(EscapeSequences_1.C0.ESC + '[?'
- + (this._terminal.buffer.y + 1)
- + ';'
- + (this._terminal.buffer.x + 1)
- + 'R');
- break;
- case 15:
- break;
- case 25:
- break;
- case 26:
- break;
- case 53:
- break;
- }
- }
- };
- InputHandler.prototype.softReset = function (params) {
- this._terminal.cursorHidden = false;
- this._terminal.insertMode = false;
- this._terminal.originMode = false;
- this._terminal.wraparoundMode = true;
- this._terminal.applicationKeypad = false;
- this._terminal.viewport.syncScrollArea();
- this._terminal.applicationCursor = false;
- this._terminal.buffer.scrollTop = 0;
- this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
- this._terminal.curAttr = this._terminal.defAttr;
- this._terminal.buffer.x = this._terminal.buffer.y = 0;
- this._terminal.charset = null;
- this._terminal.glevel = 0;
- this._terminal.charsets = [null];
- };
- InputHandler.prototype.setCursorStyle = function (params) {
- var param = params[0] < 1 ? 1 : params[0];
- switch (param) {
- case 1:
- case 2:
- this._terminal.setOption('cursorStyle', 'block');
- break;
- case 3:
- case 4:
- this._terminal.setOption('cursorStyle', 'underline');
- break;
- case 5:
- case 6:
- this._terminal.setOption('cursorStyle', 'bar');
- break;
- }
- var isBlinking = param % 2 === 1;
- this._terminal.setOption('cursorBlink', isBlinking);
- };
- InputHandler.prototype.setScrollRegion = function (params) {
- if (this._terminal.prefix)
- return;
- this._terminal.buffer.scrollTop = (params[0] || 1) - 1;
- this._terminal.buffer.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1;
- this._terminal.buffer.x = 0;
- this._terminal.buffer.y = 0;
- };
- InputHandler.prototype.saveCursor = function (params) {
- this._terminal.buffer.savedX = this._terminal.buffer.x;
- this._terminal.buffer.savedY = this._terminal.buffer.y;
- };
- InputHandler.prototype.restoreCursor = function (params) {
- this._terminal.buffer.x = this._terminal.buffer.savedX || 0;
- this._terminal.buffer.y = this._terminal.buffer.savedY || 0;
- };
- return InputHandler;
-}());
-exports.InputHandler = InputHandler;
-exports.wcwidth = (function (opts) {
- var COMBINING_BMP = [
- [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489],
- [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2],
- [0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603],
- [0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670],
- [0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED],
- [0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A],
- [0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902],
- [0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D],
- [0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981],
- [0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD],
- [0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C],
- [0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D],
- [0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC],
- [0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD],
- [0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C],
- [0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D],
- [0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0],
- [0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48],
- [0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC],
- [0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD],
- [0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D],
- [0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6],
- [0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E],
- [0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC],
- [0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35],
- [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E],
- [0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97],
- [0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030],
- [0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039],
- [0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F],
- [0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753],
- [0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD],
- [0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD],
- [0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922],
- [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B],
- [0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34],
- [0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42],
- [0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF],
- [0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063],
- [0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F],
- [0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B],
- [0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F],
- [0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB],
- ];
- var COMBINING_HIGH = [
- [0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F],
- [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169],
- [0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD],
- [0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F],
- [0xE0100, 0xE01EF]
- ];
- function bisearch(ucs, data) {
- var min = 0;
- var max = data.length - 1;
- var mid;
- if (ucs < data[0][0] || ucs > data[max][1])
- return false;
- while (max >= min) {
- mid = (min + max) >> 1;
- if (ucs > data[mid][1])
- min = mid + 1;
- else if (ucs < data[mid][0])
- max = mid - 1;
- else
- return true;
- }
- return false;
- }
- function wcwidthBMP(ucs) {
- if (ucs === 0)
- return opts.nul;
- if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
- return opts.control;
- if (bisearch(ucs, COMBINING_BMP))
- return 0;
- if (isWideBMP(ucs)) {
- return 2;
- }
- return 1;
- }
- function isWideBMP(ucs) {
- return (ucs >= 0x1100 && (ucs <= 0x115f ||
- ucs === 0x2329 ||
- ucs === 0x232a ||
- (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs !== 0x303f) ||
- (ucs >= 0xac00 && ucs <= 0xd7a3) ||
- (ucs >= 0xf900 && ucs <= 0xfaff) ||
- (ucs >= 0xfe10 && ucs <= 0xfe19) ||
- (ucs >= 0xfe30 && ucs <= 0xfe6f) ||
- (ucs >= 0xff00 && ucs <= 0xff60) ||
- (ucs >= 0xffe0 && ucs <= 0xffe6)));
- }
- function wcwidthHigh(ucs) {
- if (bisearch(ucs, COMBINING_HIGH))
- return 0;
- if ((ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd)) {
- return 2;
- }
- return 1;
- }
- var control = opts.control | 0;
- var table = null;
- function init_table() {
- var CODEPOINTS = 65536;
- var BITWIDTH = 2;
- var ITEMSIZE = 32;
- var CONTAINERSIZE = CODEPOINTS * BITWIDTH / ITEMSIZE;
- var CODEPOINTS_PER_ITEM = ITEMSIZE / BITWIDTH;
- table = (typeof Uint32Array === 'undefined')
- ? new Array(CONTAINERSIZE)
- : new Uint32Array(CONTAINERSIZE);
- for (var i = 0; i < CONTAINERSIZE; ++i) {
- var num = 0;
- var pos = CODEPOINTS_PER_ITEM;
- while (pos--)
- num = (num << 2) | wcwidthBMP(CODEPOINTS_PER_ITEM * i + pos);
- table[i] = num;
- }
- return table;
- }
- return function (num) {
- num = num | 0;
- if (num < 32)
- return control | 0;
- if (num < 127)
- return 1;
- var t = table || init_table();
- if (num < 65536)
- return t[num >> 4] >> ((num & 15) << 1) & 3;
- return wcwidthHigh(num);
- };
-})({ nul: 0, control: 0 });
-
-
-
-},{"./Charsets":3,"./EscapeSequences":5}],8:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var INVALID_LINK_CLASS = 'xterm-invalid-link';
-var protocolClause = '(https?:\\/\\/)';
-var domainCharacterSet = '[\\da-z\\.-]+';
-var negatedDomainCharacterSet = '[^\\da-z\\.-]+';
-var domainBodyClause = '(' + domainCharacterSet + ')';
-var tldClause = '([a-z\\.]{2,6})';
-var ipClause = '((\\d{1,3}\\.){3}\\d{1,3})';
-var localHostClause = '(localhost)';
-var portClause = '(:\\d{1,5})';
-var hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + '|' + localHostClause + ')' + portClause + '?';
-var pathClause = '(\\/[\\/\\w\\.\\-%~]*)*';
-var queryStringHashFragmentCharacterSet = '[0-9\\w\\[\\]\\(\\)\\/\\?\\!#@$%&\'*+,:;~\\=\\.\\-]*';
-var queryStringClause = '(\\?' + queryStringHashFragmentCharacterSet + ')?';
-var hashFragmentClause = '(#' + queryStringHashFragmentCharacterSet + ')?';
-var negatedPathCharacterSet = '[^\\/\\w\\.\\-%]+';
-var bodyClause = hostClause + pathClause + queryStringClause + hashFragmentClause;
-var start = '(?:^|' + negatedDomainCharacterSet + ')(';
-var end = ')($|' + negatedPathCharacterSet + ')';
-var strictUrlRegex = new RegExp(start + protocolClause + bodyClause + end);
-var HYPERTEXT_LINK_MATCHER_ID = 0;
-var Linkifier = (function () {
- function Linkifier() {
- this._nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID;
- this._rowTimeoutIds = [];
- this._linkMatchers = [];
- this.registerLinkMatcher(strictUrlRegex, null, { matchIndex: 1 });
- }
- Linkifier.prototype.attachToDom = function (document, rows) {
- this._document = document;
- this._rows = rows;
- };
- Linkifier.prototype.linkifyRow = function (rowIndex) {
- if (!this._document) {
- return;
- }
- var timeoutId = this._rowTimeoutIds[rowIndex];
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- this._rowTimeoutIds[rowIndex] = setTimeout(this._linkifyRow.bind(this, rowIndex), Linkifier.TIME_BEFORE_LINKIFY);
- };
- Linkifier.prototype.setHypertextLinkHandler = function (handler) {
- this._linkMatchers[HYPERTEXT_LINK_MATCHER_ID].handler = handler;
- };
- Linkifier.prototype.setHypertextValidationCallback = function (callback) {
- this._linkMatchers[HYPERTEXT_LINK_MATCHER_ID].validationCallback = callback;
- };
- Linkifier.prototype.registerLinkMatcher = function (regex, handler, options) {
- if (options === void 0) { options = {}; }
- if (this._nextLinkMatcherId !== HYPERTEXT_LINK_MATCHER_ID && !handler) {
- throw new Error('handler must be defined');
- }
- var matcher = {
- id: this._nextLinkMatcherId++,
- regex: regex,
- handler: handler,
- matchIndex: options.matchIndex,
- validationCallback: options.validationCallback,
- priority: options.priority || 0
- };
- this._addLinkMatcherToList(matcher);
- return matcher.id;
- };
- Linkifier.prototype._addLinkMatcherToList = function (matcher) {
- if (this._linkMatchers.length === 0) {
- this._linkMatchers.push(matcher);
- return;
- }
- for (var i = this._linkMatchers.length - 1; i >= 0; i--) {
- if (matcher.priority <= this._linkMatchers[i].priority) {
- this._linkMatchers.splice(i + 1, 0, matcher);
- return;
- }
- }
- this._linkMatchers.splice(0, 0, matcher);
- };
- Linkifier.prototype.deregisterLinkMatcher = function (matcherId) {
- for (var i = 1; i < this._linkMatchers.length; i++) {
- if (this._linkMatchers[i].id === matcherId) {
- this._linkMatchers.splice(i, 1);
- return true;
- }
- }
- return false;
- };
- Linkifier.prototype._linkifyRow = function (rowIndex) {
- var row = this._rows[rowIndex];
- if (!row) {
- return;
- }
- var text = row.textContent;
- for (var i = 0; i < this._linkMatchers.length; i++) {
- var matcher = this._linkMatchers[i];
- var linkElements = this._doLinkifyRow(row, matcher);
- if (linkElements.length > 0) {
- if (matcher.validationCallback) {
- var _loop_1 = function (j) {
- var element = linkElements[j];
- matcher.validationCallback(element.textContent, element, function (isValid) {
- if (!isValid) {
- element.classList.add(INVALID_LINK_CLASS);
- }
- });
- };
- for (var j = 0; j < linkElements.length; j++) {
- _loop_1(j);
- }
- }
- return;
- }
- }
- };
- Linkifier.prototype._doLinkifyRow = function (row, matcher) {
- var result = [];
- var isHttpLinkMatcher = matcher.id === HYPERTEXT_LINK_MATCHER_ID;
- var nodes = row.childNodes;
- var match = row.textContent.match(matcher.regex);
- if (!match || match.length === 0) {
- return result;
- }
- var uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex];
- var rowStartIndex = match.index + uri.length;
- for (var i = 0; i < nodes.length; i++) {
- var node = nodes[i];
- var searchIndex = node.textContent.indexOf(uri);
- if (searchIndex >= 0) {
- var linkElement = this._createAnchorElement(uri, matcher.handler, isHttpLinkMatcher);
- if (node.textContent.length === uri.length) {
- if (node.nodeType === 3) {
- this._replaceNode(node, linkElement);
- }
- else {
- var element = node;
- if (element.nodeName === 'A') {
- return result;
- }
- element.innerHTML = '';
- element.appendChild(linkElement);
- }
- }
- else if (node.childNodes.length > 1) {
- for (var j = 0; j < node.childNodes.length; j++) {
- var childNode = node.childNodes[j];
- var childSearchIndex = childNode.textContent.indexOf(uri);
- if (childSearchIndex !== -1) {
- this._replaceNodeSubstringWithNode(childNode, linkElement, uri, childSearchIndex);
- break;
- }
- }
- }
- else {
- var nodesAdded = this._replaceNodeSubstringWithNode(node, linkElement, uri, searchIndex);
- i += nodesAdded;
- }
- result.push(linkElement);
- match = row.textContent.substring(rowStartIndex).match(matcher.regex);
- if (!match || match.length === 0) {
- return result;
- }
- uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex];
- rowStartIndex += match.index + uri.length;
- }
- }
- return result;
- };
- Linkifier.prototype._createAnchorElement = function (uri, handler, isHypertextLinkHandler) {
- var element = this._document.createElement('a');
- element.textContent = uri;
- element.draggable = false;
- if (isHypertextLinkHandler) {
- element.href = uri;
- element.target = '_blank';
- element.addEventListener('click', function (event) {
- if (handler) {
- return handler(event, uri);
- }
- });
- }
- else {
- element.addEventListener('click', function (event) {
- if (element.classList.contains(INVALID_LINK_CLASS)) {
- return;
- }
- return handler(event, uri);
- });
- }
- return element;
- };
- Linkifier.prototype._replaceNode = function (oldNode) {
- var newNodes = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- newNodes[_i - 1] = arguments[_i];
- }
- var parent = oldNode.parentNode;
- for (var i = 0; i < newNodes.length; i++) {
- parent.insertBefore(newNodes[i], oldNode);
- }
- parent.removeChild(oldNode);
- };
- Linkifier.prototype._replaceNodeSubstringWithNode = function (targetNode, newNode, substring, substringIndex) {
- if (targetNode.childNodes.length === 1) {
- targetNode = targetNode.childNodes[0];
- }
- if (targetNode.nodeType !== 3) {
- throw new Error('targetNode must be a text node or only contain a single text node');
- }
- var fullText = targetNode.textContent;
- if (substringIndex === 0) {
- var rightText_1 = fullText.substring(substring.length);
- var rightTextNode_1 = this._document.createTextNode(rightText_1);
- this._replaceNode(targetNode, newNode, rightTextNode_1);
- return 0;
- }
- if (substringIndex === targetNode.textContent.length - substring.length) {
- var leftText_1 = fullText.substring(0, substringIndex);
- var leftTextNode_1 = this._document.createTextNode(leftText_1);
- this._replaceNode(targetNode, leftTextNode_1, newNode);
- return 0;
- }
- var leftText = fullText.substring(0, substringIndex);
- var leftTextNode = this._document.createTextNode(leftText);
- var rightText = fullText.substring(substringIndex + substring.length);
- var rightTextNode = this._document.createTextNode(rightText);
- this._replaceNode(targetNode, leftTextNode, newNode, rightTextNode);
- return 1;
- };
- return Linkifier;
-}());
-Linkifier.TIME_BEFORE_LINKIFY = 200;
-exports.Linkifier = Linkifier;
-
-
-
-},{}],9:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var EscapeSequences_1 = require("./EscapeSequences");
-var Charsets_1 = require("./Charsets");
-var normalStateHandler = {};
-normalStateHandler[EscapeSequences_1.C0.BEL] = function (parser, handler) { return handler.bell(); };
-normalStateHandler[EscapeSequences_1.C0.LF] = function (parser, handler) { return handler.lineFeed(); };
-normalStateHandler[EscapeSequences_1.C0.VT] = normalStateHandler[EscapeSequences_1.C0.LF];
-normalStateHandler[EscapeSequences_1.C0.FF] = normalStateHandler[EscapeSequences_1.C0.LF];
-normalStateHandler[EscapeSequences_1.C0.CR] = function (parser, handler) { return handler.carriageReturn(); };
-normalStateHandler[EscapeSequences_1.C0.BS] = function (parser, handler) { return handler.backspace(); };
-normalStateHandler[EscapeSequences_1.C0.HT] = function (parser, handler) { return handler.tab(); };
-normalStateHandler[EscapeSequences_1.C0.SO] = function (parser, handler) { return handler.shiftOut(); };
-normalStateHandler[EscapeSequences_1.C0.SI] = function (parser, handler) { return handler.shiftIn(); };
-normalStateHandler[EscapeSequences_1.C0.ESC] = function (parser, handler) { return parser.setState(ParserState.ESCAPED); };
-var escapedStateHandler = {};
-escapedStateHandler['['] = function (parser, terminal) {
- terminal.params = [];
- terminal.currentParam = 0;
- parser.setState(ParserState.CSI_PARAM);
-};
-escapedStateHandler[']'] = function (parser, terminal) {
- terminal.params = [];
- terminal.currentParam = 0;
- parser.setState(ParserState.OSC);
-};
-escapedStateHandler['P'] = function (parser, terminal) {
- terminal.params = [];
- terminal.currentParam = 0;
- parser.setState(ParserState.DCS);
-};
-escapedStateHandler['_'] = function (parser, terminal) {
- parser.setState(ParserState.IGNORE);
-};
-escapedStateHandler['^'] = function (parser, terminal) {
- parser.setState(ParserState.IGNORE);
-};
-escapedStateHandler['c'] = function (parser, terminal) {
- terminal.reset();
-};
-escapedStateHandler['E'] = function (parser, terminal) {
- terminal.buffer.x = 0;
- terminal.index();
- parser.setState(ParserState.NORMAL);
-};
-escapedStateHandler['D'] = function (parser, terminal) {
- terminal.index();
- parser.setState(ParserState.NORMAL);
-};
-escapedStateHandler['M'] = function (parser, terminal) {
- terminal.reverseIndex();
- parser.setState(ParserState.NORMAL);
-};
-escapedStateHandler['%'] = function (parser, terminal) {
- terminal.setgLevel(0);
- terminal.setgCharset(0, Charsets_1.DEFAULT_CHARSET);
- parser.setState(ParserState.NORMAL);
- parser.skipNextChar();
-};
-escapedStateHandler[EscapeSequences_1.C0.CAN] = function (parser) { return parser.setState(ParserState.NORMAL); };
-var csiParamStateHandler = {};
-csiParamStateHandler['?'] = function (parser) { return parser.setPrefix('?'); };
-csiParamStateHandler['>'] = function (parser) { return parser.setPrefix('>'); };
-csiParamStateHandler['!'] = function (parser) { return parser.setPrefix('!'); };
-csiParamStateHandler['0'] = function (parser) { return parser.setParam(parser.getParam() * 10); };
-csiParamStateHandler['1'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 1); };
-csiParamStateHandler['2'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 2); };
-csiParamStateHandler['3'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 3); };
-csiParamStateHandler['4'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 4); };
-csiParamStateHandler['5'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 5); };
-csiParamStateHandler['6'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 6); };
-csiParamStateHandler['7'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 7); };
-csiParamStateHandler['8'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 8); };
-csiParamStateHandler['9'] = function (parser) { return parser.setParam(parser.getParam() * 10 + 9); };
-csiParamStateHandler['$'] = function (parser) { return parser.setPostfix('$'); };
-csiParamStateHandler['"'] = function (parser) { return parser.setPostfix('"'); };
-csiParamStateHandler[' '] = function (parser) { return parser.setPostfix(' '); };
-csiParamStateHandler['\''] = function (parser) { return parser.setPostfix('\''); };
-csiParamStateHandler[';'] = function (parser) { return parser.finalizeParam(); };
-csiParamStateHandler[EscapeSequences_1.C0.CAN] = function (parser) { return parser.setState(ParserState.NORMAL); };
-var csiStateHandler = {};
-csiStateHandler['@'] = function (handler, params, prefix) { return handler.insertChars(params); };
-csiStateHandler['A'] = function (handler, params, prefix) { return handler.cursorUp(params); };
-csiStateHandler['B'] = function (handler, params, prefix) { return handler.cursorDown(params); };
-csiStateHandler['C'] = function (handler, params, prefix) { return handler.cursorForward(params); };
-csiStateHandler['D'] = function (handler, params, prefix) { return handler.cursorBackward(params); };
-csiStateHandler['E'] = function (handler, params, prefix) { return handler.cursorNextLine(params); };
-csiStateHandler['F'] = function (handler, params, prefix) { return handler.cursorPrecedingLine(params); };
-csiStateHandler['G'] = function (handler, params, prefix) { return handler.cursorCharAbsolute(params); };
-csiStateHandler['H'] = function (handler, params, prefix) { return handler.cursorPosition(params); };
-csiStateHandler['I'] = function (handler, params, prefix) { return handler.cursorForwardTab(params); };
-csiStateHandler['J'] = function (handler, params, prefix) { return handler.eraseInDisplay(params); };
-csiStateHandler['K'] = function (handler, params, prefix) { return handler.eraseInLine(params); };
-csiStateHandler['L'] = function (handler, params, prefix) { return handler.insertLines(params); };
-csiStateHandler['M'] = function (handler, params, prefix) { return handler.deleteLines(params); };
-csiStateHandler['P'] = function (handler, params, prefix) { return handler.deleteChars(params); };
-csiStateHandler['S'] = function (handler, params, prefix) { return handler.scrollUp(params); };
-csiStateHandler['T'] = function (handler, params, prefix) {
- if (params.length < 2 && !prefix) {
- handler.scrollDown(params);
- }
-};
-csiStateHandler['X'] = function (handler, params, prefix) { return handler.eraseChars(params); };
-csiStateHandler['Z'] = function (handler, params, prefix) { return handler.cursorBackwardTab(params); };
-csiStateHandler['`'] = function (handler, params, prefix) { return handler.charPosAbsolute(params); };
-csiStateHandler['a'] = function (handler, params, prefix) { return handler.HPositionRelative(params); };
-csiStateHandler['b'] = function (handler, params, prefix) { return handler.repeatPrecedingCharacter(params); };
-csiStateHandler['c'] = function (handler, params, prefix) { return handler.sendDeviceAttributes(params); };
-csiStateHandler['d'] = function (handler, params, prefix) { return handler.linePosAbsolute(params); };
-csiStateHandler['e'] = function (handler, params, prefix) { return handler.VPositionRelative(params); };
-csiStateHandler['f'] = function (handler, params, prefix) { return handler.HVPosition(params); };
-csiStateHandler['g'] = function (handler, params, prefix) { return handler.tabClear(params); };
-csiStateHandler['h'] = function (handler, params, prefix) { return handler.setMode(params); };
-csiStateHandler['l'] = function (handler, params, prefix) { return handler.resetMode(params); };
-csiStateHandler['m'] = function (handler, params, prefix) { return handler.charAttributes(params); };
-csiStateHandler['n'] = function (handler, params, prefix) { return handler.deviceStatus(params); };
-csiStateHandler['p'] = function (handler, params, prefix) {
- switch (prefix) {
- case '!':
- handler.softReset(params);
- break;
- }
-};
-csiStateHandler['q'] = function (handler, params, prefix, postfix) {
- if (postfix === ' ') {
- handler.setCursorStyle(params);
- }
-};
-csiStateHandler['r'] = function (handler, params) { return handler.setScrollRegion(params); };
-csiStateHandler['s'] = function (handler, params) { return handler.saveCursor(params); };
-csiStateHandler['u'] = function (handler, params) { return handler.restoreCursor(params); };
-csiStateHandler[EscapeSequences_1.C0.CAN] = function (handler, params, prefix, postfix, parser) { return parser.setState(ParserState.NORMAL); };
-var ParserState;
-(function (ParserState) {
- ParserState[ParserState["NORMAL"] = 0] = "NORMAL";
- ParserState[ParserState["ESCAPED"] = 1] = "ESCAPED";
- ParserState[ParserState["CSI_PARAM"] = 2] = "CSI_PARAM";
- ParserState[ParserState["CSI"] = 3] = "CSI";
- ParserState[ParserState["OSC"] = 4] = "OSC";
- ParserState[ParserState["CHARSET"] = 5] = "CHARSET";
- ParserState[ParserState["DCS"] = 6] = "DCS";
- ParserState[ParserState["IGNORE"] = 7] = "IGNORE";
-})(ParserState || (ParserState = {}));
-var Parser = (function () {
- function Parser(_inputHandler, _terminal) {
- this._inputHandler = _inputHandler;
- this._terminal = _terminal;
- this._state = ParserState.NORMAL;
- }
- Parser.prototype.parse = function (data) {
- var l = data.length, j, cs, ch, code, low;
- if (this._terminal.debug) {
- this._terminal.log('data: ' + data);
- }
- this._position = 0;
- if (this._terminal.surrogate_high) {
- data = this._terminal.surrogate_high + data;
- this._terminal.surrogate_high = '';
- }
- for (; this._position < l; this._position++) {
- ch = data[this._position];
- code = data.charCodeAt(this._position);
- if (0xD800 <= code && code <= 0xDBFF) {
- low = data.charCodeAt(this._position + 1);
- if (isNaN(low)) {
- this._terminal.surrogate_high = ch;
- continue;
- }
- code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
- ch += data.charAt(this._position + 1);
- }
- if (0xDC00 <= code && code <= 0xDFFF)
- continue;
- switch (this._state) {
- case ParserState.NORMAL:
- if (ch in normalStateHandler) {
- normalStateHandler[ch](this, this._inputHandler);
- }
- else {
- this._inputHandler.addChar(ch, code);
- }
- break;
- case ParserState.ESCAPED:
- if (ch in escapedStateHandler) {
- escapedStateHandler[ch](this, this._terminal);
- break;
- }
- switch (ch) {
- case '(':
- case ')':
- case '*':
- case '+':
- case '-':
- case '.':
- switch (ch) {
- case '(':
- this._terminal.gcharset = 0;
- break;
- case ')':
- this._terminal.gcharset = 1;
- break;
- case '*':
- this._terminal.gcharset = 2;
- break;
- case '+':
- this._terminal.gcharset = 3;
- break;
- case '-':
- this._terminal.gcharset = 1;
- break;
- case '.':
- this._terminal.gcharset = 2;
- break;
- }
- this._state = ParserState.CHARSET;
- break;
- case '/':
- this._terminal.gcharset = 3;
- this._state = ParserState.CHARSET;
- this._position--;
- break;
- case 'N':
- break;
- case 'O':
- break;
- case 'n':
- this._terminal.setgLevel(2);
- break;
- case 'o':
- this._terminal.setgLevel(3);
- break;
- case '|':
- this._terminal.setgLevel(3);
- break;
- case '}':
- this._terminal.setgLevel(2);
- break;
- case '~':
- this._terminal.setgLevel(1);
- break;
- case '7':
- this._inputHandler.saveCursor();
- this._state = ParserState.NORMAL;
- break;
- case '8':
- this._inputHandler.restoreCursor();
- this._state = ParserState.NORMAL;
- break;
- case '#':
- this._state = ParserState.NORMAL;
- this._position++;
- break;
- case 'H':
- this._terminal.tabSet();
- this._state = ParserState.NORMAL;
- break;
- case '=':
- this._terminal.log('Serial port requested application keypad.');
- this._terminal.applicationKeypad = true;
- this._terminal.viewport.syncScrollArea();
- this._state = ParserState.NORMAL;
- break;
- case '>':
- this._terminal.log('Switching back to normal keypad.');
- this._terminal.applicationKeypad = false;
- this._terminal.viewport.syncScrollArea();
- this._state = ParserState.NORMAL;
- break;
- default:
- this._state = ParserState.NORMAL;
- this._terminal.error('Unknown ESC control: %s.', ch);
- break;
- }
- break;
- case ParserState.CHARSET:
- if (ch in Charsets_1.CHARSETS) {
- cs = Charsets_1.CHARSETS[ch];
- if (ch === '/') {
- this.skipNextChar();
- }
- }
- else {
- cs = Charsets_1.DEFAULT_CHARSET;
- }
- this._terminal.setgCharset(this._terminal.gcharset, cs);
- this._terminal.gcharset = null;
- this._state = ParserState.NORMAL;
- break;
- case ParserState.OSC:
- if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) {
- if (ch === EscapeSequences_1.C0.ESC)
- this._position++;
- this._terminal.params.push(this._terminal.currentParam);
- switch (this._terminal.params[0]) {
- case 0:
- case 1:
- case 2:
- if (this._terminal.params[1]) {
- this._terminal.title = this._terminal.params[1];
- this._terminal.handleTitle(this._terminal.title);
- }
- break;
- case 3:
- break;
- case 4:
- case 5:
- break;
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
- case 19:
- break;
- case 46:
- break;
- case 50:
- break;
- case 51:
- break;
- case 52:
- break;
- case 104:
- case 105:
- case 110:
- case 111:
- case 112:
- case 113:
- case 114:
- case 115:
- case 116:
- case 117:
- case 118:
- break;
- }
- this._terminal.params = [];
- this._terminal.currentParam = 0;
- this._state = ParserState.NORMAL;
- }
- else {
- if (!this._terminal.params.length) {
- if (ch >= '0' && ch <= '9') {
- this._terminal.currentParam =
- this._terminal.currentParam * 10 + ch.charCodeAt(0) - 48;
- }
- else if (ch === ';') {
- this._terminal.params.push(this._terminal.currentParam);
- this._terminal.currentParam = '';
- }
- }
- else {
- this._terminal.currentParam += ch;
- }
- }
- break;
- case ParserState.CSI_PARAM:
- if (ch in csiParamStateHandler) {
- csiParamStateHandler[ch](this);
- break;
- }
- this.finalizeParam();
- this._state = ParserState.CSI;
- case ParserState.CSI:
- if (ch in csiStateHandler) {
- if (this._terminal.debug) {
- this._terminal.log("CSI " + (this._terminal.prefix ? this._terminal.prefix : '') + " " + (this._terminal.params ? this._terminal.params.join(';') : '') + " " + (this._terminal.postfix ? this._terminal.postfix : '') + " " + ch);
- }
- csiStateHandler[ch](this._inputHandler, this._terminal.params, this._terminal.prefix, this._terminal.postfix, this);
- }
- else {
- this._terminal.error('Unknown CSI code: %s.', ch);
- }
- this._state = ParserState.NORMAL;
- this._terminal.prefix = '';
- this._terminal.postfix = '';
- break;
- case ParserState.DCS:
- if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) {
- if (ch === EscapeSequences_1.C0.ESC)
- this._position++;
- var pt = void 0;
- var valid = void 0;
- switch (this._terminal.prefix) {
- case '':
- break;
- case '$q':
- pt = this._terminal.currentParam;
- valid = false;
- switch (pt) {
- case '"q':
- pt = '0"q';
- break;
- case '"p':
- pt = '61"p';
- break;
- case 'r':
- pt = ''
- + (this._terminal.buffer.scrollTop + 1)
- + ';'
- + (this._terminal.buffer.scrollBottom + 1)
- + 'r';
- break;
- case 'm':
- pt = '0m';
- break;
- default:
- this._terminal.error('Unknown DCS Pt: %s.', pt);
- pt = '';
- break;
- }
- this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '$r' + pt + EscapeSequences_1.C0.ESC + '\\');
- break;
- case '+p':
- break;
- case '+q':
- pt = this._terminal.currentParam;
- valid = false;
- this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '+r' + pt + EscapeSequences_1.C0.ESC + '\\');
- break;
- default:
- this._terminal.error('Unknown DCS prefix: %s.', this._terminal.prefix);
- break;
- }
- this._terminal.currentParam = 0;
- this._terminal.prefix = '';
- this._state = ParserState.NORMAL;
- }
- else if (!this._terminal.currentParam) {
- if (!this._terminal.prefix && ch !== '$' && ch !== '+') {
- this._terminal.currentParam = ch;
- }
- else if (this._terminal.prefix.length === 2) {
- this._terminal.currentParam = ch;
- }
- else {
- this._terminal.prefix += ch;
- }
- }
- else {
- this._terminal.currentParam += ch;
- }
- break;
- case ParserState.IGNORE:
- if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) {
- if (ch === EscapeSequences_1.C0.ESC)
- this._position++;
- this._state = ParserState.NORMAL;
- }
- break;
- }
- }
- return this._state;
- };
- Parser.prototype.setState = function (state) {
- this._state = state;
- };
- Parser.prototype.setPrefix = function (prefix) {
- this._terminal.prefix = prefix;
- };
- Parser.prototype.setPostfix = function (postfix) {
- this._terminal.postfix = postfix;
- };
- Parser.prototype.setParam = function (param) {
- this._terminal.currentParam = param;
- };
- Parser.prototype.getParam = function () {
- return this._terminal.currentParam;
- };
- Parser.prototype.finalizeParam = function () {
- this._terminal.params.push(this._terminal.currentParam);
- this._terminal.currentParam = 0;
- };
- Parser.prototype.skipNextChar = function () {
- this._position++;
- };
- return Parser;
-}());
-exports.Parser = Parser;
-
-
-
-},{"./Charsets":3,"./EscapeSequences":5}],10:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var DomElementObjectPool_1 = require("./utils/DomElementObjectPool");
-var MAX_REFRESH_FRAME_SKIP = 5;
-var FLAGS;
-(function (FLAGS) {
- FLAGS[FLAGS["BOLD"] = 1] = "BOLD";
- FLAGS[FLAGS["UNDERLINE"] = 2] = "UNDERLINE";
- FLAGS[FLAGS["BLINK"] = 4] = "BLINK";
- FLAGS[FLAGS["INVERSE"] = 8] = "INVERSE";
- FLAGS[FLAGS["INVISIBLE"] = 16] = "INVISIBLE";
-})(FLAGS || (FLAGS = {}));
-;
-var brokenBold = null;
-var Renderer = (function () {
- function Renderer(_terminal) {
- this._terminal = _terminal;
- this._refreshRowsQueue = [];
- this._refreshFramesSkipped = 0;
- this._refreshAnimationFrame = null;
- this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span');
- if (brokenBold === null) {
- brokenBold = checkBoldBroken(this._terminal.element);
- }
- this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span');
- }
- Renderer.prototype.queueRefresh = function (start, end) {
- this._refreshRowsQueue.push({ start: start, end: end });
- if (!this._refreshAnimationFrame) {
- this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this));
- }
- };
- Renderer.prototype._refreshLoop = function () {
- var skipFrame = this._terminal.writeBuffer.length > 0 && this._refreshFramesSkipped++ <= MAX_REFRESH_FRAME_SKIP;
- if (skipFrame) {
- this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this));
- return;
- }
- this._refreshFramesSkipped = 0;
- var start;
- var end;
- if (this._refreshRowsQueue.length > 4) {
- start = 0;
- end = this._terminal.rows - 1;
- }
- else {
- start = this._refreshRowsQueue[0].start;
- end = this._refreshRowsQueue[0].end;
- for (var i = 1; i < this._refreshRowsQueue.length; i++) {
- if (this._refreshRowsQueue[i].start < start) {
- start = this._refreshRowsQueue[i].start;
- }
- if (this._refreshRowsQueue[i].end > end) {
- end = this._refreshRowsQueue[i].end;
- }
- }
- }
- this._refreshRowsQueue = [];
- this._refreshAnimationFrame = null;
- this._refresh(start, end);
- };
- Renderer.prototype._refresh = function (start, end) {
- var parent;
- if (end - start >= this._terminal.rows / 2) {
- parent = this._terminal.element.parentNode;
- if (parent) {
- this._terminal.element.removeChild(this._terminal.rowContainer);
- }
- }
- var width = this._terminal.cols;
- var y = start;
- if (end >= this._terminal.rows) {
- this._terminal.log('`end` is too large. Most likely a bad CSR.');
- end = this._terminal.rows - 1;
- }
- for (; y <= end; y++) {
- var row = y + this._terminal.buffer.ydisp;
- var line = this._terminal.buffer.lines.get(row);
- var x = void 0;
- if (this._terminal.buffer.y === y - (this._terminal.buffer.ybase - this._terminal.buffer.ydisp) &&
- this._terminal.cursorState &&
- !this._terminal.cursorHidden) {
- x = this._terminal.buffer.x;
- }
- else {
- x = -1;
- }
- var attr = this._terminal.defAttr;
- var documentFragment = document.createDocumentFragment();
- var innerHTML = '';
- var currentElement = void 0;
- while (this._terminal.children[y].children.length) {
- var child = this._terminal.children[y].children[0];
- this._terminal.children[y].removeChild(child);
- this._spanElementObjectPool.release(child);
- }
- for (var i = 0; i < width; i++) {
- var data = line[i][0];
- var ch = line[i][1];
- var ch_width = line[i][2];
- var isCursor = i === x;
- if (!ch_width) {
- continue;
- }
- if (data !== attr || isCursor) {
- if (attr !== this._terminal.defAttr && !isCursor) {
- if (innerHTML) {
- currentElement.innerHTML = innerHTML;
- innerHTML = '';
- }
- documentFragment.appendChild(currentElement);
- currentElement = null;
- }
- if (data !== this._terminal.defAttr || isCursor) {
- if (innerHTML && !currentElement) {
- currentElement = this._spanElementObjectPool.acquire();
- }
- if (currentElement) {
- if (innerHTML) {
- currentElement.innerHTML = innerHTML;
- innerHTML = '';
- }
- documentFragment.appendChild(currentElement);
- }
- currentElement = this._spanElementObjectPool.acquire();
- var bg = data & 0x1ff;
- var fg = (data >> 9) & 0x1ff;
- var flags = data >> 18;
- if (isCursor) {
- currentElement.classList.add('reverse-video');
- currentElement.classList.add('terminal-cursor');
- }
- if (flags & FLAGS.BOLD) {
- if (!brokenBold) {
- currentElement.classList.add('xterm-bold');
- }
- if (fg < 8) {
- fg += 8;
- }
- }
- if (flags & FLAGS.UNDERLINE) {
- currentElement.classList.add('xterm-underline');
- }
- if (flags & FLAGS.BLINK) {
- currentElement.classList.add('xterm-blink');
- }
- if (flags & FLAGS.INVERSE) {
- var temp = bg;
- bg = fg;
- fg = temp;
- if ((flags & 1) && fg < 8) {
- fg += 8;
- }
- }
- if (flags & FLAGS.INVISIBLE && !isCursor) {
- currentElement.classList.add('xterm-hidden');
- }
- if (flags & FLAGS.INVERSE) {
- if (bg === 257) {
- bg = 15;
- }
- if (fg === 256) {
- fg = 0;
- }
- }
- if (bg < 256) {
- currentElement.classList.add("xterm-bg-color-" + bg);
- }
- if (fg < 256) {
- currentElement.classList.add("xterm-color-" + fg);
- }
- }
- }
- if (ch_width === 2) {
- innerHTML += "" + ch + " ";
- }
- else if (ch.charCodeAt(0) > 255) {
- innerHTML += "" + ch + " ";
- }
- else {
- switch (ch) {
- case '&':
- innerHTML += '&';
- break;
- case '<':
- innerHTML += '<';
- break;
- case '>':
- innerHTML += '>';
- break;
- default:
- if (ch <= ' ') {
- innerHTML += ' ';
- }
- else {
- innerHTML += ch;
- }
- break;
- }
- }
- attr = isCursor ? -1 : data;
- }
- if (innerHTML && !currentElement) {
- currentElement = this._spanElementObjectPool.acquire();
- }
- if (currentElement) {
- if (innerHTML) {
- currentElement.innerHTML = innerHTML;
- innerHTML = '';
- }
- documentFragment.appendChild(currentElement);
- currentElement = null;
- }
- this._terminal.children[y].appendChild(documentFragment);
- }
- if (parent) {
- this._terminal.element.appendChild(this._terminal.rowContainer);
- }
- this._terminal.emit('refresh', { element: this._terminal.element, start: start, end: end });
- };
- ;
- Renderer.prototype.refreshSelection = function (start, end) {
- while (this._terminal.selectionContainer.children.length) {
- this._terminal.selectionContainer.removeChild(this._terminal.selectionContainer.children[0]);
- }
- if (!start || !end) {
- return;
- }
- var viewportStartRow = start[1] - this._terminal.buffer.ydisp;
- var viewportEndRow = end[1] - this._terminal.buffer.ydisp;
- var viewportCappedStartRow = Math.max(viewportStartRow, 0);
- var viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1);
- if (viewportCappedStartRow >= this._terminal.rows || viewportCappedEndRow < 0) {
- return;
- }
- var documentFragment = document.createDocumentFragment();
- var startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
- var endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
- documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
- var middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
- documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._terminal.cols, middleRowsCount));
- if (viewportCappedStartRow !== viewportCappedEndRow) {
- var endCol_1 = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
- documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol_1));
- }
- this._terminal.selectionContainer.appendChild(documentFragment);
- };
- Renderer.prototype._createSelectionElement = function (row, colStart, colEnd, rowCount) {
- if (rowCount === void 0) { rowCount = 1; }
- var element = document.createElement('div');
- element.style.height = rowCount * this._terminal.charMeasure.height + "px";
- element.style.top = row * this._terminal.charMeasure.height + "px";
- element.style.left = colStart * this._terminal.charMeasure.width + "px";
- element.style.width = this._terminal.charMeasure.width * (colEnd - colStart) + "px";
- return element;
- };
- return Renderer;
-}());
-exports.Renderer = Renderer;
-function checkBoldBroken(terminal) {
- var document = terminal.ownerDocument;
- var el = document.createElement('span');
- el.innerHTML = 'hello world';
- terminal.appendChild(el);
- var w1 = el.offsetWidth;
- var h1 = el.offsetHeight;
- el.style.fontWeight = 'bold';
- var w2 = el.offsetWidth;
- var h2 = el.offsetHeight;
- terminal.removeChild(el);
- return w1 !== w2 || h1 !== h2;
-}
-
-
-
-},{"./utils/DomElementObjectPool":19}],11:[function(require,module,exports){
-"use strict";
-var __extends = (this && this.__extends) || (function () {
- var extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
- return function (d, b) {
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- };
-})();
-Object.defineProperty(exports, "__esModule", { value: true });
-var Mouse = require("./utils/Mouse");
-var Browser = require("./utils/Browser");
-var EventEmitter_1 = require("./EventEmitter");
-var SelectionModel_1 = require("./SelectionModel");
-var BufferLine_1 = require("./utils/BufferLine");
-var DRAG_SCROLL_MAX_THRESHOLD = 50;
-var DRAG_SCROLL_MAX_SPEED = 15;
-var DRAG_SCROLL_INTERVAL = 50;
-var WORD_SEPARATORS = ' ()[]{}\'"';
-var LINE_DATA_CHAR_INDEX = 1;
-var LINE_DATA_WIDTH_INDEX = 2;
-var NON_BREAKING_SPACE_CHAR = String.fromCharCode(160);
-var ALL_NON_BREAKING_SPACE_REGEX = new RegExp(NON_BREAKING_SPACE_CHAR, 'g');
-var SelectionMode;
-(function (SelectionMode) {
- SelectionMode[SelectionMode["NORMAL"] = 0] = "NORMAL";
- SelectionMode[SelectionMode["WORD"] = 1] = "WORD";
- SelectionMode[SelectionMode["LINE"] = 2] = "LINE";
-})(SelectionMode || (SelectionMode = {}));
-var SelectionManager = (function (_super) {
- __extends(SelectionManager, _super);
- function SelectionManager(_terminal, _buffer, _rowContainer, _charMeasure) {
- var _this = _super.call(this) || this;
- _this._terminal = _terminal;
- _this._buffer = _buffer;
- _this._rowContainer = _rowContainer;
- _this._charMeasure = _charMeasure;
- _this._enabled = true;
- _this._initListeners();
- _this.enable();
- _this._model = new SelectionModel_1.SelectionModel(_terminal);
- _this._activeSelectionMode = SelectionMode.NORMAL;
- return _this;
- }
- SelectionManager.prototype._initListeners = function () {
- var _this = this;
- this._mouseMoveListener = function (event) { return _this._onMouseMove(event); };
- this._mouseUpListener = function (event) { return _this._onMouseUp(event); };
- this._rowContainer.addEventListener('mousedown', function (event) { return _this._onMouseDown(event); });
- this._buffer.on('trim', function (amount) { return _this._onTrim(amount); });
- };
- SelectionManager.prototype.disable = function () {
- this.clearSelection();
- this._enabled = false;
- };
- SelectionManager.prototype.enable = function () {
- this._enabled = true;
- };
- SelectionManager.prototype.setBuffer = function (buffer) {
- this._buffer = buffer;
- this.clearSelection();
- };
- Object.defineProperty(SelectionManager.prototype, "selectionStart", {
- get: function () { return this._model.finalSelectionStart; },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(SelectionManager.prototype, "selectionEnd", {
- get: function () { return this._model.finalSelectionEnd; },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(SelectionManager.prototype, "hasSelection", {
- get: function () {
- var start = this._model.finalSelectionStart;
- var end = this._model.finalSelectionEnd;
- if (!start || !end) {
- return false;
- }
- return start[0] !== end[0] || start[1] !== end[1];
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(SelectionManager.prototype, "selectionText", {
- get: function () {
- var start = this._model.finalSelectionStart;
- var end = this._model.finalSelectionEnd;
- if (!start || !end) {
- return '';
- }
- var startRowEndCol = start[1] === end[1] ? end[0] : null;
- var result = [];
- result.push(BufferLine_1.translateBufferLineToString(this._buffer.get(start[1]), true, start[0], startRowEndCol));
- for (var i = start[1] + 1; i <= end[1] - 1; i++) {
- var bufferLine = this._buffer.get(i);
- var lineText = BufferLine_1.translateBufferLineToString(bufferLine, true);
- if (bufferLine.isWrapped) {
- result[result.length - 1] += lineText;
- }
- else {
- result.push(lineText);
- }
- }
- if (start[1] !== end[1]) {
- var bufferLine = this._buffer.get(end[1]);
- var lineText = BufferLine_1.translateBufferLineToString(bufferLine, true, 0, end[0]);
- if (bufferLine.isWrapped) {
- result[result.length - 1] += lineText;
- }
- else {
- result.push(lineText);
- }
- }
- var formattedResult = result.map(function (line) {
- return line.replace(ALL_NON_BREAKING_SPACE_REGEX, ' ');
- }).join(Browser.isMSWindows ? '\r\n' : '\n');
- return formattedResult;
- },
- enumerable: true,
- configurable: true
- });
- SelectionManager.prototype.clearSelection = function () {
- this._model.clearSelection();
- this._removeMouseDownListeners();
- this.refresh();
- };
- SelectionManager.prototype.refresh = function (isNewSelection) {
- var _this = this;
- if (!this._refreshAnimationFrame) {
- this._refreshAnimationFrame = window.requestAnimationFrame(function () { return _this._refresh(); });
- }
- if (Browser.isLinux && isNewSelection) {
- var selectionText = this.selectionText;
- if (selectionText.length) {
- this.emit('newselection', this.selectionText);
- }
- }
- };
- SelectionManager.prototype._refresh = function () {
- this._refreshAnimationFrame = null;
- this.emit('refresh', { start: this._model.finalSelectionStart, end: this._model.finalSelectionEnd });
- };
- SelectionManager.prototype.selectAll = function () {
- this._model.isSelectAllActive = true;
- this.refresh();
- };
- SelectionManager.prototype._onTrim = function (amount) {
- var needsRefresh = this._model.onTrim(amount);
- if (needsRefresh) {
- this.refresh();
- }
- };
- SelectionManager.prototype._getMouseBufferCoords = function (event) {
- var coords = Mouse.getCoords(event, this._rowContainer, this._charMeasure, this._terminal.cols, this._terminal.rows, true);
- if (!coords) {
- return null;
- }
- coords[0]--;
- coords[1]--;
- coords[1] += this._terminal.buffer.ydisp;
- return coords;
- };
- SelectionManager.prototype._getMouseEventScrollAmount = function (event) {
- var offset = Mouse.getCoordsRelativeToElement(event, this._rowContainer)[1];
- var terminalHeight = this._terminal.rows * this._charMeasure.height;
- if (offset >= 0 && offset <= terminalHeight) {
- return 0;
- }
- if (offset > terminalHeight) {
- offset -= terminalHeight;
- }
- offset = Math.min(Math.max(offset, -DRAG_SCROLL_MAX_THRESHOLD), DRAG_SCROLL_MAX_THRESHOLD);
- offset /= DRAG_SCROLL_MAX_THRESHOLD;
- return (offset / Math.abs(offset)) + Math.round(offset * (DRAG_SCROLL_MAX_SPEED - 1));
- };
- SelectionManager.prototype._onMouseDown = function (event) {
- if (event.button === 2 && this.hasSelection) {
- event.stopPropagation();
- return;
- }
- if (event.button !== 0) {
- return;
- }
- if (!this._enabled) {
- var shouldForceSelection = Browser.isMac && event.altKey;
- if (!shouldForceSelection) {
- return;
- }
- event.stopPropagation();
- }
- event.preventDefault();
- this._dragScrollAmount = 0;
- if (this._enabled && event.shiftKey) {
- this._onIncrementalClick(event);
- }
- else {
- if (event.detail === 1) {
- this._onSingleClick(event);
- }
- else if (event.detail === 2) {
- this._onDoubleClick(event);
- }
- else if (event.detail === 3) {
- this._onTripleClick(event);
- }
- }
- this._addMouseDownListeners();
- this.refresh(true);
- };
- SelectionManager.prototype._addMouseDownListeners = function () {
- var _this = this;
- this._rowContainer.ownerDocument.addEventListener('mousemove', this._mouseMoveListener);
- this._rowContainer.ownerDocument.addEventListener('mouseup', this._mouseUpListener);
- this._dragScrollIntervalTimer = setInterval(function () { return _this._dragScroll(); }, DRAG_SCROLL_INTERVAL);
- };
- SelectionManager.prototype._removeMouseDownListeners = function () {
- this._rowContainer.ownerDocument.removeEventListener('mousemove', this._mouseMoveListener);
- this._rowContainer.ownerDocument.removeEventListener('mouseup', this._mouseUpListener);
- clearInterval(this._dragScrollIntervalTimer);
- this._dragScrollIntervalTimer = null;
- };
- SelectionManager.prototype._onIncrementalClick = function (event) {
- if (this._model.selectionStart) {
- this._model.selectionEnd = this._getMouseBufferCoords(event);
- }
- };
- SelectionManager.prototype._onSingleClick = function (event) {
- this._model.selectionStartLength = 0;
- this._model.isSelectAllActive = false;
- this._activeSelectionMode = SelectionMode.NORMAL;
- this._model.selectionStart = this._getMouseBufferCoords(event);
- if (!this._model.selectionStart) {
- return;
- }
- this._model.selectionEnd = null;
- var line = this._buffer.get(this._model.selectionStart[1]);
- if (!line) {
- return;
- }
- var char = line[this._model.selectionStart[0]];
- if (char[LINE_DATA_WIDTH_INDEX] === 0) {
- this._model.selectionStart[0]++;
- }
- };
- SelectionManager.prototype._onDoubleClick = function (event) {
- var coords = this._getMouseBufferCoords(event);
- if (coords) {
- this._activeSelectionMode = SelectionMode.WORD;
- this._selectWordAt(coords);
- }
- };
- SelectionManager.prototype._onTripleClick = function (event) {
- var coords = this._getMouseBufferCoords(event);
- if (coords) {
- this._activeSelectionMode = SelectionMode.LINE;
- this._selectLineAt(coords[1]);
- }
- };
- SelectionManager.prototype._onMouseMove = function (event) {
- var previousSelectionEnd = this._model.selectionEnd ? [this._model.selectionEnd[0], this._model.selectionEnd[1]] : null;
- this._model.selectionEnd = this._getMouseBufferCoords(event);
- if (!this._model.selectionEnd) {
- this.refresh(true);
- return;
- }
- if (this._activeSelectionMode === SelectionMode.LINE) {
- if (this._model.selectionEnd[1] < this._model.selectionStart[1]) {
- this._model.selectionEnd[0] = 0;
- }
- else {
- this._model.selectionEnd[0] = this._terminal.cols;
- }
- }
- else if (this._activeSelectionMode === SelectionMode.WORD) {
- this._selectToWordAt(this._model.selectionEnd);
- }
- this._dragScrollAmount = this._getMouseEventScrollAmount(event);
- if (this._dragScrollAmount > 0) {
- this._model.selectionEnd[0] = this._terminal.cols - 1;
- }
- else if (this._dragScrollAmount < 0) {
- this._model.selectionEnd[0] = 0;
- }
- if (this._model.selectionEnd[1] < this._buffer.length) {
- var char = this._buffer.get(this._model.selectionEnd[1])[this._model.selectionEnd[0]];
- if (char && char[2] === 0) {
- this._model.selectionEnd[0]++;
- }
- }
- if (!previousSelectionEnd ||
- previousSelectionEnd[0] !== this._model.selectionEnd[0] ||
- previousSelectionEnd[1] !== this._model.selectionEnd[1]) {
- this.refresh(true);
- }
- };
- SelectionManager.prototype._dragScroll = function () {
- if (this._dragScrollAmount) {
- this._terminal.scrollDisp(this._dragScrollAmount, false);
- if (this._dragScrollAmount > 0) {
- this._model.selectionEnd = [this._terminal.cols - 1, this._terminal.buffer.ydisp + this._terminal.rows];
- }
- else {
- this._model.selectionEnd = [0, this._terminal.buffer.ydisp];
- }
- this.refresh();
- }
- };
- SelectionManager.prototype._onMouseUp = function (event) {
- this._removeMouseDownListeners();
- };
- SelectionManager.prototype._convertViewportColToCharacterIndex = function (bufferLine, coords) {
- var charIndex = coords[0];
- for (var i = 0; coords[0] >= i; i++) {
- var char = bufferLine[i];
- if (char[LINE_DATA_WIDTH_INDEX] === 0) {
- charIndex--;
- }
- }
- return charIndex;
- };
- SelectionManager.prototype.setSelection = function (col, row, length) {
- this._model.clearSelection();
- this._removeMouseDownListeners();
- this._model.selectionStart = [col, row];
- this._model.selectionStartLength = length;
- this.refresh();
- };
- SelectionManager.prototype._getWordAt = function (coords) {
- var bufferLine = this._buffer.get(coords[1]);
- if (!bufferLine) {
- return null;
- }
- var line = BufferLine_1.translateBufferLineToString(bufferLine, false);
- var endIndex = this._convertViewportColToCharacterIndex(bufferLine, coords);
- var startIndex = endIndex;
- var charOffset = coords[0] - startIndex;
- var leftWideCharCount = 0;
- var rightWideCharCount = 0;
- if (line.charAt(startIndex) === ' ') {
- while (startIndex > 0 && line.charAt(startIndex - 1) === ' ') {
- startIndex--;
- }
- while (endIndex < line.length && line.charAt(endIndex + 1) === ' ') {
- endIndex++;
- }
- }
- else {
- var startCol = coords[0];
- var endCol = coords[0];
- if (bufferLine[startCol][LINE_DATA_WIDTH_INDEX] === 0) {
- leftWideCharCount++;
- startCol--;
- }
- if (bufferLine[endCol][LINE_DATA_WIDTH_INDEX] === 2) {
- rightWideCharCount++;
- endCol++;
- }
- while (startIndex > 0 && !this._isCharWordSeparator(line.charAt(startIndex - 1))) {
- if (bufferLine[startCol - 1][LINE_DATA_WIDTH_INDEX] === 0) {
- leftWideCharCount++;
- startCol--;
- }
- startIndex--;
- startCol--;
- }
- while (endIndex + 1 < line.length && !this._isCharWordSeparator(line.charAt(endIndex + 1))) {
- if (bufferLine[endCol + 1][LINE_DATA_WIDTH_INDEX] === 2) {
- rightWideCharCount++;
- endCol++;
- }
- endIndex++;
- endCol++;
- }
- }
- var start = startIndex + charOffset - leftWideCharCount;
- var length = Math.min(endIndex - startIndex + leftWideCharCount + rightWideCharCount + 1, this._terminal.cols);
- return { start: start, length: length };
- };
- SelectionManager.prototype._selectWordAt = function (coords) {
- var wordPosition = this._getWordAt(coords);
- if (wordPosition) {
- this._model.selectionStart = [wordPosition.start, coords[1]];
- this._model.selectionStartLength = wordPosition.length;
- }
- };
- SelectionManager.prototype._selectToWordAt = function (coords) {
- var wordPosition = this._getWordAt(coords);
- if (wordPosition) {
- this._model.selectionEnd = [this._model.areSelectionValuesReversed() ? wordPosition.start : (wordPosition.start + wordPosition.length), coords[1]];
- }
- };
- SelectionManager.prototype._isCharWordSeparator = function (char) {
- return WORD_SEPARATORS.indexOf(char) >= 0;
- };
- SelectionManager.prototype._selectLineAt = function (line) {
- this._model.selectionStart = [0, line];
- this._model.selectionStartLength = this._terminal.cols;
- };
- return SelectionManager;
-}(EventEmitter_1.EventEmitter));
-exports.SelectionManager = SelectionManager;
-
-
-
-},{"./EventEmitter":6,"./SelectionModel":12,"./utils/Browser":15,"./utils/BufferLine":16,"./utils/Mouse":21}],12:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var SelectionModel = (function () {
- function SelectionModel(_terminal) {
- this._terminal = _terminal;
- this.clearSelection();
- }
- SelectionModel.prototype.clearSelection = function () {
- this.selectionStart = null;
- this.selectionEnd = null;
- this.isSelectAllActive = false;
- this.selectionStartLength = 0;
- };
- Object.defineProperty(SelectionModel.prototype, "finalSelectionStart", {
- get: function () {
- if (this.isSelectAllActive) {
- return [0, 0];
- }
- if (!this.selectionEnd || !this.selectionStart) {
- return this.selectionStart;
- }
- return this.areSelectionValuesReversed() ? this.selectionEnd : this.selectionStart;
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(SelectionModel.prototype, "finalSelectionEnd", {
- get: function () {
- if (this.isSelectAllActive) {
- return [this._terminal.cols, this._terminal.buffer.ybase + this._terminal.rows - 1];
- }
- if (!this.selectionStart) {
- return null;
- }
- if (!this.selectionEnd || this.areSelectionValuesReversed()) {
- return [this.selectionStart[0] + this.selectionStartLength, this.selectionStart[1]];
- }
- if (this.selectionStartLength) {
- if (this.selectionEnd[1] === this.selectionStart[1]) {
- return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]];
- }
- }
- return this.selectionEnd;
- },
- enumerable: true,
- configurable: true
- });
- SelectionModel.prototype.areSelectionValuesReversed = function () {
- var start = this.selectionStart;
- var end = this.selectionEnd;
- return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]);
- };
- SelectionModel.prototype.onTrim = function (amount) {
- if (this.selectionStart) {
- this.selectionStart[1] -= amount;
- }
- if (this.selectionEnd) {
- this.selectionEnd[1] -= amount;
- }
- if (this.selectionEnd && this.selectionEnd[1] < 0) {
- this.clearSelection();
- return true;
- }
- if (this.selectionStart && this.selectionStart[1] < 0) {
- this.selectionStart[1] = 0;
- }
- return false;
- };
- return SelectionModel;
-}());
-exports.SelectionModel = SelectionModel;
-
-
-
-},{}],13:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var Viewport = (function () {
- function Viewport(terminal, viewportElement, scrollArea, charMeasure) {
- var _this = this;
- this.terminal = terminal;
- this.viewportElement = viewportElement;
- this.scrollArea = scrollArea;
- this.charMeasure = charMeasure;
- this.currentRowHeight = 0;
- this.lastRecordedBufferLength = 0;
- this.lastRecordedViewportHeight = 0;
- this.terminal.on('scroll', this.syncScrollArea.bind(this));
- this.terminal.on('resize', this.syncScrollArea.bind(this));
- this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
- setTimeout(function () { return _this.syncScrollArea(); }, 0);
- }
- Viewport.prototype.refresh = function () {
- if (this.charMeasure.height > 0) {
- var rowHeightChanged = this.charMeasure.height !== this.currentRowHeight;
- if (rowHeightChanged) {
- this.currentRowHeight = this.charMeasure.height;
- this.viewportElement.style.lineHeight = this.charMeasure.height + 'px';
- this.terminal.rowContainer.style.lineHeight = this.charMeasure.height + 'px';
- }
- var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows;
- if (rowHeightChanged || viewportHeightChanged) {
- this.lastRecordedViewportHeight = this.terminal.rows;
- this.viewportElement.style.height = this.charMeasure.height * this.terminal.rows + 'px';
- this.terminal.selectionContainer.style.height = this.viewportElement.style.height;
- }
- this.scrollArea.style.height = (this.charMeasure.height * this.lastRecordedBufferLength) + 'px';
- }
- };
- Viewport.prototype.syncScrollArea = function () {
- if (this.lastRecordedBufferLength !== this.terminal.buffer.lines.length) {
- this.lastRecordedBufferLength = this.terminal.buffer.lines.length;
- this.refresh();
- }
- else if (this.lastRecordedViewportHeight !== this.terminal.rows) {
- this.refresh();
- }
- else {
- if (this.charMeasure.height !== this.currentRowHeight) {
- this.refresh();
- }
- }
- var scrollTop = this.terminal.buffer.ydisp * this.currentRowHeight;
- if (this.viewportElement.scrollTop !== scrollTop) {
- this.viewportElement.scrollTop = scrollTop;
- }
- };
- Viewport.prototype.onScroll = function (ev) {
- var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight);
- var diff = newRow - this.terminal.buffer.ydisp;
- this.terminal.scrollDisp(diff, true);
- };
- Viewport.prototype.onWheel = function (ev) {
- if (ev.deltaY === 0) {
- return;
- }
- var multiplier = 1;
- if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) {
- multiplier = this.currentRowHeight;
- }
- else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
- multiplier = this.currentRowHeight * this.terminal.rows;
- }
- this.viewportElement.scrollTop += ev.deltaY * multiplier;
- ev.preventDefault();
- };
- ;
- Viewport.prototype.onTouchStart = function (ev) {
- this.lastTouchY = ev.touches[0].pageY;
- };
- ;
- Viewport.prototype.onTouchMove = function (ev) {
- var deltaY = this.lastTouchY - ev.touches[0].pageY;
- this.lastTouchY = ev.touches[0].pageY;
- if (deltaY === 0) {
- return;
- }
- this.viewportElement.scrollTop += deltaY;
- ev.preventDefault();
- };
- ;
- return Viewport;
-}());
-exports.Viewport = Viewport;
-
-
-
-},{}],14:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-function prepareTextForTerminal(text, isMSWindows) {
- if (isMSWindows) {
- return text.replace(/\r?\n/g, '\r');
- }
- return text;
-}
-exports.prepareTextForTerminal = prepareTextForTerminal;
-function copyHandler(ev, term, selectionManager) {
- if (term.browser.isMSIE) {
- window.clipboardData.setData('Text', selectionManager.selectionText);
- }
- else {
- ev.clipboardData.setData('text/plain', selectionManager.selectionText);
- }
- ev.preventDefault();
-}
-exports.copyHandler = copyHandler;
-function pasteHandler(ev, term) {
- ev.stopPropagation();
- var text;
- var dispatchPaste = function (text) {
- text = prepareTextForTerminal(text, term.browser.isMSWindows);
- term.handler(text);
- term.textarea.value = '';
- term.emit('paste', text);
- return term.cancel(ev);
- };
- if (term.browser.isMSIE) {
- if (window.clipboardData) {
- text = window.clipboardData.getData('Text');
- dispatchPaste(text);
- }
- }
- else {
- if (ev.clipboardData) {
- text = ev.clipboardData.getData('text/plain');
- dispatchPaste(text);
- }
- }
-}
-exports.pasteHandler = pasteHandler;
-function moveTextAreaUnderMouseCursor(ev, textarea) {
- textarea.style.position = 'fixed';
- textarea.style.width = '20px';
- textarea.style.height = '20px';
- textarea.style.left = (ev.clientX - 10) + 'px';
- textarea.style.top = (ev.clientY - 10) + 'px';
- textarea.style.zIndex = '1000';
- textarea.focus();
- setTimeout(function () {
- textarea.style.position = null;
- textarea.style.width = null;
- textarea.style.height = null;
- textarea.style.left = null;
- textarea.style.top = null;
- textarea.style.zIndex = null;
- }, 4);
-}
-exports.moveTextAreaUnderMouseCursor = moveTextAreaUnderMouseCursor;
-function rightClickHandler(ev, textarea, selectionManager) {
- moveTextAreaUnderMouseCursor(ev, textarea);
- textarea.value = selectionManager.selectionText;
- textarea.select();
-}
-exports.rightClickHandler = rightClickHandler;
-
-
-
-},{}],15:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var Generic_1 = require("./Generic");
-var isNode = (typeof navigator === 'undefined') ? true : false;
-var userAgent = (isNode) ? 'node' : navigator.userAgent;
-var platform = (isNode) ? 'node' : navigator.platform;
-exports.isFirefox = !!~userAgent.indexOf('Firefox');
-exports.isMSIE = !!~userAgent.indexOf('MSIE') || !!~userAgent.indexOf('Trident');
-exports.isMac = Generic_1.contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform);
-exports.isIpad = platform === 'iPad';
-exports.isIphone = platform === 'iPhone';
-exports.isMSWindows = Generic_1.contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform);
-exports.isLinux = platform.indexOf('Linux') >= 0;
-
-
-
-},{"./Generic":20}],16:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var LINE_DATA_CHAR_INDEX = 1;
-var LINE_DATA_WIDTH_INDEX = 2;
-function translateBufferLineToString(line, trimRight, startCol, endCol) {
- if (startCol === void 0) { startCol = 0; }
- if (endCol === void 0) { endCol = null; }
- var lineString = '';
- var widthAdjustedStartCol = startCol;
- var widthAdjustedEndCol = endCol;
- for (var i = 0; i < line.length; i++) {
- var char = line[i];
- lineString += char[LINE_DATA_CHAR_INDEX];
- if (char[LINE_DATA_WIDTH_INDEX] === 0) {
- if (startCol >= i) {
- widthAdjustedStartCol--;
- }
- if (endCol >= i) {
- widthAdjustedEndCol--;
- }
- }
- }
- var finalEndCol = widthAdjustedEndCol || line.length;
- if (trimRight) {
- var rightWhitespaceIndex = lineString.search(/\s+$/);
- if (rightWhitespaceIndex !== -1) {
- finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex);
- }
- if (finalEndCol <= widthAdjustedStartCol) {
- return '';
- }
- }
- return lineString.substring(widthAdjustedStartCol, finalEndCol);
-}
-exports.translateBufferLineToString = translateBufferLineToString;
-
-
-
-},{}],17:[function(require,module,exports){
-"use strict";
-var __extends = (this && this.__extends) || (function () {
- var extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
- return function (d, b) {
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- };
-})();
-Object.defineProperty(exports, "__esModule", { value: true });
-var EventEmitter_js_1 = require("../EventEmitter.js");
-var CharMeasure = (function (_super) {
- __extends(CharMeasure, _super);
- function CharMeasure(document, parentElement) {
- var _this = _super.call(this) || this;
- _this._document = document;
- _this._parentElement = parentElement;
- return _this;
- }
- Object.defineProperty(CharMeasure.prototype, "width", {
- get: function () {
- return this._width;
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(CharMeasure.prototype, "height", {
- get: function () {
- return this._height;
- },
- enumerable: true,
- configurable: true
- });
- CharMeasure.prototype.measure = function () {
- var _this = this;
- if (!this._measureElement) {
- this._measureElement = this._document.createElement('span');
- this._measureElement.style.position = 'absolute';
- this._measureElement.style.top = '0';
- this._measureElement.style.left = '-9999em';
- this._measureElement.textContent = 'W';
- this._measureElement.setAttribute('aria-hidden', 'true');
- this._parentElement.appendChild(this._measureElement);
- setTimeout(function () { return _this._doMeasure(); }, 0);
- }
- else {
- this._doMeasure();
- }
- };
- CharMeasure.prototype._doMeasure = function () {
- var geometry = this._measureElement.getBoundingClientRect();
- if (geometry.width === 0 || geometry.height === 0) {
- return;
- }
- if (this._width !== geometry.width || this._height !== geometry.height) {
- this._width = geometry.width;
- this._height = geometry.height;
- this.emit('charsizechanged');
- }
- };
- return CharMeasure;
-}(EventEmitter_js_1.EventEmitter));
-exports.CharMeasure = CharMeasure;
-
-
-
-},{"../EventEmitter.js":6}],18:[function(require,module,exports){
-"use strict";
-var __extends = (this && this.__extends) || (function () {
- var extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
- return function (d, b) {
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- };
-})();
-Object.defineProperty(exports, "__esModule", { value: true });
-var EventEmitter_1 = require("../EventEmitter");
-var CircularList = (function (_super) {
- __extends(CircularList, _super);
- function CircularList(maxLength) {
- var _this = _super.call(this) || this;
- _this._array = new Array(maxLength);
- _this._startIndex = 0;
- _this._length = 0;
- return _this;
- }
- Object.defineProperty(CircularList.prototype, "maxLength", {
- get: function () {
- return this._array.length;
- },
- set: function (newMaxLength) {
- var newArray = new Array(newMaxLength);
- for (var i = 0; i < Math.min(newMaxLength, this.length); i++) {
- newArray[i] = this._array[this._getCyclicIndex(i)];
- }
- this._array = newArray;
- this._startIndex = 0;
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(CircularList.prototype, "length", {
- get: function () {
- return this._length;
- },
- set: function (newLength) {
- if (newLength > this._length) {
- for (var i = this._length; i < newLength; i++) {
- this._array[i] = undefined;
- }
- }
- this._length = newLength;
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(CircularList.prototype, "forEach", {
- get: function () {
- var _this = this;
- return function (callbackfn) {
- var i = 0;
- var length = _this.length;
- for (var i_1 = 0; i_1 < length; i_1++) {
- callbackfn(_this.get(i_1), i_1);
- }
- };
- },
- enumerable: true,
- configurable: true
- });
- CircularList.prototype.get = function (index) {
- return this._array[this._getCyclicIndex(index)];
- };
- CircularList.prototype.set = function (index, value) {
- this._array[this._getCyclicIndex(index)] = value;
- };
- CircularList.prototype.push = function (value) {
- this._array[this._getCyclicIndex(this._length)] = value;
- if (this._length === this.maxLength) {
- this._startIndex++;
- if (this._startIndex === this.maxLength) {
- this._startIndex = 0;
- }
- this.emit('trim', 1);
- }
- else {
- this._length++;
- }
- };
- CircularList.prototype.pop = function () {
- return this._array[this._getCyclicIndex(this._length-- - 1)];
- };
- CircularList.prototype.splice = function (start, deleteCount) {
- var items = [];
- for (var _i = 2; _i < arguments.length; _i++) {
- items[_i - 2] = arguments[_i];
- }
- if (deleteCount) {
- for (var i = start; i < this._length - deleteCount; i++) {
- this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)];
- }
- this._length -= deleteCount;
- }
- if (items && items.length) {
- for (var i = this._length - 1; i >= start; i--) {
- this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)];
- }
- for (var i = 0; i < items.length; i++) {
- this._array[this._getCyclicIndex(start + i)] = items[i];
- }
- if (this._length + items.length > this.maxLength) {
- var countToTrim = (this._length + items.length) - this.maxLength;
- this._startIndex += countToTrim;
- this._length = this.maxLength;
- this.emit('trim', countToTrim);
- }
- else {
- this._length += items.length;
- }
- }
- };
- CircularList.prototype.trimStart = function (count) {
- if (count > this._length) {
- count = this._length;
- }
- this._startIndex += count;
- this._length -= count;
- this.emit('trim', count);
- };
- CircularList.prototype.shiftElements = function (start, count, offset) {
- if (count <= 0) {
- return;
- }
- if (start < 0 || start >= this._length) {
- throw new Error('start argument out of range');
- }
- if (start + offset < 0) {
- throw new Error('Cannot shift elements in list beyond index 0');
- }
- if (offset > 0) {
- for (var i = count - 1; i >= 0; i--) {
- this.set(start + i + offset, this.get(start + i));
- }
- var expandListBy = (start + count + offset) - this._length;
- if (expandListBy > 0) {
- this._length += expandListBy;
- while (this._length > this.maxLength) {
- this._length--;
- this._startIndex++;
- this.emit('trim', 1);
- }
- }
- }
- else {
- for (var i = 0; i < count; i++) {
- this.set(start + i + offset, this.get(start + i));
- }
- }
- };
- CircularList.prototype._getCyclicIndex = function (index) {
- return (this._startIndex + index) % this.maxLength;
- };
- return CircularList;
-}(EventEmitter_1.EventEmitter));
-exports.CircularList = CircularList;
-
-
-
-},{"../EventEmitter":6}],19:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var DomElementObjectPool = (function () {
- function DomElementObjectPool(type) {
- this.type = type;
- this._type = type;
- this._pool = [];
- this._inUse = {};
- }
- DomElementObjectPool.prototype.acquire = function () {
- var element;
- if (this._pool.length === 0) {
- element = this._createNew();
- }
- else {
- element = this._pool.pop();
- }
- this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)] = element;
- return element;
- };
- DomElementObjectPool.prototype.release = function (element) {
- if (!this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]) {
- throw new Error('Could not release an element not yet acquired');
- }
- delete this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)];
- this._cleanElement(element);
- this._pool.push(element);
- };
- DomElementObjectPool.prototype._createNew = function () {
- var element = document.createElement(this._type);
- var id = DomElementObjectPool._objectCount++;
- element.setAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE, id.toString(10));
- return element;
- };
- DomElementObjectPool.prototype._cleanElement = function (element) {
- element.className = '';
- element.innerHTML = '';
- };
- return DomElementObjectPool;
-}());
-DomElementObjectPool.OBJECT_ID_ATTRIBUTE = 'data-obj-id';
-DomElementObjectPool._objectCount = 0;
-exports.DomElementObjectPool = DomElementObjectPool;
-
-
-
},{}],20:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-function contains(arr, el) {
- return arr.indexOf(el) >= 0;
-}
-exports.contains = contains;
-;
-
-
-
-},{}],21:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-function getCoordsRelativeToElement(event, element) {
- if (event.pageX == null) {
- return null;
- }
- var x = event.pageX;
- var y = event.pageY;
- while (element && element !== self.document.documentElement) {
- x -= element.offsetLeft;
- y -= element.offsetTop;
- element = 'offsetParent' in element ? element.offsetParent : element.parentElement;
- }
- return [x, y];
-}
-exports.getCoordsRelativeToElement = getCoordsRelativeToElement;
-function getCoords(event, rowContainer, charMeasure, colCount, rowCount, isSelection) {
- if (!charMeasure.width || !charMeasure.height) {
- return null;
- }
- var coords = getCoordsRelativeToElement(event, rowContainer);
- if (!coords) {
- return null;
- }
- coords[0] = Math.ceil((coords[0] + (isSelection ? charMeasure.width / 2 : 0)) / charMeasure.width);
- coords[1] = Math.ceil(coords[1] / charMeasure.height);
- coords[0] = Math.min(Math.max(coords[0], 1), colCount + 1);
- coords[1] = Math.min(Math.max(coords[1], 1), rowCount + 1);
- return coords;
-}
-exports.getCoords = getCoords;
-function getRawByteCoords(event, rowContainer, charMeasure, colCount, rowCount) {
- var coords = getCoords(event, rowContainer, charMeasure, colCount, rowCount);
- var x = coords[0];
- var y = coords[1];
- x += 32;
- y += 32;
- return { x: x, y: y };
-}
-exports.getRawByteCoords = getRawByteCoords;
-
-
-
-},{}],22:[function(require,module,exports){
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-var BufferSet_1 = require("./BufferSet");
-var CompositionHelper_1 = require("./CompositionHelper");
-var EventEmitter_1 = require("./EventEmitter");
-var Viewport_1 = require("./Viewport");
-var Clipboard_1 = require("./handlers/Clipboard");
-var EscapeSequences_1 = require("./EscapeSequences");
-var InputHandler_1 = require("./InputHandler");
-var Parser_1 = require("./Parser");
-var Renderer_1 = require("./Renderer");
-var Linkifier_1 = require("./Linkifier");
-var SelectionManager_1 = require("./SelectionManager");
-var CharMeasure_1 = require("./utils/CharMeasure");
-var Browser = require("./utils/Browser");
-var Mouse_1 = require("./utils/Mouse");
-var BufferLine_1 = require("./utils/BufferLine");
-var document = (typeof window != 'undefined') ? window.document : null;
-var WRITE_BUFFER_PAUSE_THRESHOLD = 5;
-var WRITE_BATCH_SIZE = 300;
-var CURSOR_BLINK_INTERVAL = 600;
-function Terminal(options) {
- var self = this;
- if (!(this instanceof Terminal)) {
- return new Terminal(arguments[0], arguments[1], arguments[2]);
- }
- self.browser = Browser;
- self.cancel = Terminal.cancel;
- EventEmitter_1.EventEmitter.call(this);
- if (typeof options === 'number') {
- options = {
- cols: arguments[0],
- rows: arguments[1],
- handler: arguments[2]
- };
- }
- options = options || {};
- Object.keys(Terminal.defaults).forEach(function (key) {
- if (options[key] == null) {
- options[key] = Terminal.options[key];
- 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.concat(Terminal._colors.slice(16, -2), options.colors.slice(-2));
- }
- this.colors = options.colors;
- this.options = options;
- 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];
- this.geometry = [this.cols, this.rows];
- if (options.handler) {
- this.on('data', options.handler);
- }
- this.cursorState = 0;
- this.cursorHidden = false;
- this.convertEol;
- this.queue = '';
- this.customKeyEventHandler = null;
- this.cursorBlinkInterval = null;
- this.applicationKeypad = false;
- this.applicationCursor = false;
- this.originMode = false;
- this.insertMode = false;
- this.wraparoundMode = true;
- this.charset = null;
- this.gcharset = null;
- this.glevel = 0;
- this.charsets = [null];
- this.decLocator;
- this.x10Mouse;
- this.vt200Mouse;
- this.vt300Mouse;
- this.normalMouse;
- this.mouseEvents;
- this.sendFocus;
- this.utfMouse;
- this.sgrMouse;
- this.urxvtMouse;
- this.element;
- this.children;
- this.refreshStart;
- this.refreshEnd;
- this.savedX;
- this.savedY;
- this.savedCols;
- this.readable = true;
- this.writable = true;
- this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
- this.curAttr = this.defAttr;
- this.params = [];
- this.currentParam = 0;
- this.prefix = '';
- this.postfix = '';
- this.inputHandler = new InputHandler_1.InputHandler(this);
- this.parser = new Parser_1.Parser(this.inputHandler, this);
- this.renderer = this.renderer || null;
- this.selectionManager = this.selectionManager || null;
- this.linkifier = this.linkifier || new Linkifier_1.Linkifier();
- this.writeBuffer = [];
- this.writeInProgress = false;
- this.xoffSentToCatchUp = false;
- this.writeStopped = false;
- this.surrogate_high = '';
- this.buffers = new BufferSet_1.BufferSet(this);
- this.buffer = this.buffers.active;
- this.buffers.on('activate', function (buffer) {
- this._terminal.buffer = buffer;
- });
- if (this.selectionManager) {
- this.selectionManager.setBuffer(this.buffer.lines);
- }
- this.setupStops();
- this.userScrolling = false;
-}
-inherits(Terminal, EventEmitter_1.EventEmitter);
-Terminal.prototype.eraseAttr = function () {
- return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
+var EscapeSequences_1 = require("../../common/data/EscapeSequences");
+var KEYCODE_KEY_MAPPINGS = {
+ 48: ['0', ')'],
+ 49: ['1', '!'],
+ 50: ['2', '@'],
+ 51: ['3', '#'],
+ 52: ['4', '$'],
+ 53: ['5', '%'],
+ 54: ['6', '^'],
+ 55: ['7', '&'],
+ 56: ['8', '*'],
+ 57: ['9', '('],
+ 186: [';', ':'],
+ 187: ['=', '+'],
+ 188: [',', '<'],
+ 189: ['-', '_'],
+ 190: ['.', '>'],
+ 191: ['/', '?'],
+ 192: ['`', '~'],
+ 219: ['[', '{'],
+ 220: ['\\', '|'],
+ 221: [']', '}'],
+ 222: ['\'', '"']
};
-Terminal.tangoColors = [
- '#2e3436',
- '#cc0000',
- '#4e9a06',
- '#c4a000',
- '#3465a4',
- '#75507b',
- '#06989a',
- '#d3d7cf',
- '#555753',
- '#ef2929',
- '#8ae234',
- '#fce94f',
- '#729fcf',
- '#ad7fa8',
- '#34e2e2',
- '#eeeeec'
-];
-Terminal.colors = (function () {
- var colors = Terminal.tangoColors.slice(), r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff], i;
- i = 0;
- for (; i < 216; i++) {
- out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]);
- }
- i = 0;
- for (; i < 24; i++) {
- r = 8 + i * 10;
- out(r, r, r);
- }
- function out(r, g, b) {
- colors.push('#' + hex(r) + hex(g) + hex(b));
- }
- function hex(c) {
- c = c.toString(16);
- return c.length < 2 ? '0' + c : c;
- }
- return colors;
-})();
-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
- ]);
- }
- return out;
-})();
-Terminal.defaults = {
- colors: Terminal.colors,
- theme: 'default',
- convertEol: false,
- termName: 'xterm',
- geometry: [80, 24],
- cursorBlink: false,
- cursorStyle: 'block',
- visualBell: false,
- popOnBell: false,
- scrollback: 1000,
- screenKeys: false,
- debug: false,
- cancelEvents: false,
- disableStdin: false,
- useFlowControl: false,
- tabStopWidth: 8
-};
-Terminal.options = {};
-Terminal.focus = null;
-each(keys(Terminal.defaults), function (key) {
- Terminal[key] = Terminal.defaults[key];
- Terminal.options[key] = Terminal.defaults[key];
-});
-Terminal.prototype.focus = function () {
- return this.textarea.focus();
-};
-Terminal.prototype.getOption = function (key) {
- if (!(key in Terminal.defaults)) {
- throw new Error('No option with key "' + key + '"');
- }
- if (typeof this.options[key] !== 'undefined') {
- return this.options[key];
- }
- return this[key];
-};
-Terminal.prototype.setOption = function (key, value) {
- if (!(key in Terminal.defaults)) {
- throw new Error('No option with key "' + key + '"');
- }
- switch (key) {
- case 'scrollback':
- if (value < this.rows) {
- var msg = 'Setting the scrollback value less than the number of rows ';
- msg += "(" + this.rows + ") is not allowed.";
- console.warn(msg);
- return false;
- }
- if (this.options[key] !== value) {
- if (this.buffer.lines.length > value) {
- var amountToTrim = this.buffer.lines.length - value;
- var needsRefresh = (this.buffer.ydisp - amountToTrim < 0);
- this.buffer.lines.trimStart(amountToTrim);
- this.buffer.ybase = Math.max(this.buffer.ybase - amountToTrim, 0);
- this.buffer.ydisp = Math.max(this.buffer.ydisp - amountToTrim, 0);
- if (needsRefresh) {
- this.refresh(0, this.rows - 1);
- }
- }
- this.buffer.lines.maxLength = value;
- this.viewport.syncScrollArea();
- }
- break;
- }
- this[key] = value;
- this.options[key] = value;
- switch (key) {
- case 'cursorBlink':
- this.setCursorBlinking(value);
- break;
- case 'cursorStyle':
- this.element.classList.toggle("xterm-cursor-style-block", value === 'block');
- this.element.classList.toggle("xterm-cursor-style-underline", value === 'underline');
- this.element.classList.toggle("xterm-cursor-style-bar", value === 'bar');
- break;
- case 'tabStopWidth':
- this.setupStops();
- break;
- }
-};
-Terminal.prototype.restartCursorBlinking = function () {
- this.setCursorBlinking(this.options.cursorBlink);
-};
-Terminal.prototype.setCursorBlinking = function (enabled) {
- this.element.classList.toggle('xterm-cursor-blink', enabled);
- this.clearCursorBlinkingInterval();
- if (enabled) {
- var self = this;
- this.cursorBlinkInterval = setInterval(function () {
- self.element.classList.toggle('xterm-cursor-blink-on');
- }, CURSOR_BLINK_INTERVAL);
- }
-};
-Terminal.prototype.clearCursorBlinkingInterval = function () {
- this.element.classList.remove('xterm-cursor-blink-on');
- if (this.cursorBlinkInterval) {
- clearInterval(this.cursorBlinkInterval);
- this.cursorBlinkInterval = null;
- }
-};
-Terminal.bindFocus = function (term) {
- on(term.textarea, 'focus', function (ev) {
- if (term.sendFocus) {
- term.send(EscapeSequences_1.C0.ESC + '[I');
- }
- term.element.classList.add('focus');
- term.showCursor();
- term.restartCursorBlinking.apply(term);
- Terminal.focus = term;
- term.emit('focus', { terminal: term });
- });
-};
-Terminal.prototype.blur = function () {
- return this.textarea.blur();
-};
-Terminal.bindBlur = function (term) {
- on(term.textarea, 'blur', function (ev) {
- term.refresh(term.buffer.y, term.buffer.y);
- if (term.sendFocus) {
- term.send(EscapeSequences_1.C0.ESC + '[O');
- }
- term.element.classList.remove('focus');
- term.clearCursorBlinkingInterval.apply(term);
- Terminal.focus = null;
- term.emit('blur', { terminal: term });
- });
-};
-Terminal.prototype.initGlobal = function () {
- var _this = this;
- var term = this;
- Terminal.bindKeys(this);
- Terminal.bindFocus(this);
- Terminal.bindBlur(this);
- on(this.element, 'copy', function (event) {
- if (!term.hasSelection()) {
- return;
- }
- Clipboard_1.copyHandler(event, term, _this.selectionManager);
- });
- var pasteHandlerWrapper = function (event) { return Clipboard_1.pasteHandler(event, term); };
- on(this.textarea, 'paste', pasteHandlerWrapper);
- on(this.element, 'paste', pasteHandlerWrapper);
- if (term.browser.isFirefox) {
- on(this.element, 'mousedown', function (event) {
- if (event.button == 2) {
- Clipboard_1.rightClickHandler(event, _this.textarea, _this.selectionManager);
- }
- });
- }
- else {
- on(this.element, 'contextmenu', function (event) {
- Clipboard_1.rightClickHandler(event, _this.textarea, _this.selectionManager);
- });
- }
- if (term.browser.isLinux) {
- on(this.element, 'auxclick', function (event) {
- if (event.button === 1) {
- Clipboard_1.moveTextAreaUnderMouseCursor(event, _this.textarea, _this.selectionManager);
- }
- });
- }
-};
-Terminal.bindKeys = function (term) {
- on(term.element, 'keydown', function (ev) {
- if (document.activeElement != this) {
- return;
- }
- term.keyDown(ev);
- }, true);
- on(term.element, 'keypress', function (ev) {
- if (document.activeElement != this) {
- return;
- }
- term.keyPress(ev);
- }, true);
- on(term.element, 'keyup', function (ev) {
- if (!wasMondifierKeyOnlyEvent(ev)) {
- term.focus(term);
- }
- }, true);
- on(term.textarea, 'keydown', function (ev) {
- term.keyDown(ev);
- }, true);
- on(term.textarea, 'keypress', function (ev) {
- term.keyPress(ev);
- this.value = '';
- }, true);
- on(term.textarea, 'compositionstart', term.compositionHelper.compositionstart.bind(term.compositionHelper));
- on(term.textarea, 'compositionupdate', term.compositionHelper.compositionupdate.bind(term.compositionHelper));
- on(term.textarea, 'compositionend', term.compositionHelper.compositionend.bind(term.compositionHelper));
- term.on('refresh', term.compositionHelper.updateCompositionElements.bind(term.compositionHelper));
- term.on('refresh', function (data) {
- term.queueLinkification(data.start, data.end);
- });
-};
-Terminal.prototype.insertRow = function (row) {
- if (typeof row != 'object') {
- row = document.createElement('div');
- }
- this.rowContainer.appendChild(row);
- this.children.push(row);
- return row;
-};
-Terminal.prototype.open = function (parent, focus) {
- var _this = this;
- var self = this, i = 0, div;
- this.parent = parent || this.parent;
- if (!this.parent) {
- throw new Error('Terminal requires a parent element.');
- }
- this.context = this.parent.ownerDocument.defaultView;
- this.document = this.parent.ownerDocument;
- this.body = this.document.getElementsByTagName('body')[0];
- this.element = this.document.createElement('div');
- this.element.classList.add('terminal');
- this.element.classList.add('xterm');
- this.element.classList.add('xterm-theme-' + this.theme);
- this.element.classList.add("xterm-cursor-style-" + this.options.cursorStyle);
- this.setCursorBlinking(this.options.cursorBlink);
- this.element.setAttribute('tabindex', 0);
- this.viewportElement = document.createElement('div');
- this.viewportElement.classList.add('xterm-viewport');
- this.element.appendChild(this.viewportElement);
- this.viewportScrollArea = document.createElement('div');
- this.viewportScrollArea.classList.add('xterm-scroll-area');
- this.viewportElement.appendChild(this.viewportScrollArea);
- this.selectionContainer = document.createElement('div');
- this.selectionContainer.classList.add('xterm-selection');
- this.element.appendChild(this.selectionContainer);
- this.rowContainer = document.createElement('div');
- this.rowContainer.classList.add('xterm-rows');
- this.element.appendChild(this.rowContainer);
- this.children = [];
- this.linkifier.attachToDom(document, this.children);
- this.helperContainer = document.createElement('div');
- this.helperContainer.classList.add('xterm-helpers');
- this.element.appendChild(this.helperContainer);
- this.textarea = document.createElement('textarea');
- this.textarea.classList.add('xterm-helper-textarea');
- this.textarea.setAttribute('autocorrect', 'off');
- this.textarea.setAttribute('autocapitalize', 'off');
- this.textarea.setAttribute('spellcheck', 'false');
- this.textarea.tabIndex = 0;
- this.textarea.addEventListener('focus', function () {
- self.emit('focus', { terminal: self });
- });
- this.textarea.addEventListener('blur', function () {
- self.emit('blur', { terminal: self });
- });
- this.helperContainer.appendChild(this.textarea);
- this.compositionView = document.createElement('div');
- this.compositionView.classList.add('composition-view');
- this.compositionHelper = new CompositionHelper_1.CompositionHelper(this.textarea, this.compositionView, this);
- this.helperContainer.appendChild(this.compositionView);
- this.charSizeStyleElement = document.createElement('style');
- this.helperContainer.appendChild(this.charSizeStyleElement);
- for (; i < this.rows; i++) {
- this.insertRow();
- }
- this.parent.appendChild(this.element);
- this.charMeasure = new CharMeasure_1.CharMeasure(document, this.helperContainer);
- this.charMeasure.on('charsizechanged', function () {
- self.updateCharSizeStyles();
- });
- this.charMeasure.measure();
- this.viewport = new Viewport_1.Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure);
- this.renderer = new Renderer_1.Renderer(this);
- this.selectionManager = new SelectionManager_1.SelectionManager(this, this.buffer.lines, this.rowContainer, this.charMeasure);
- this.selectionManager.on('refresh', function (data) {
- _this.renderer.refreshSelection(data.start, data.end);
- });
- this.selectionManager.on('newselection', function (text) {
- _this.textarea.value = text;
- _this.textarea.focus();
- _this.textarea.select();
- });
- this.on('scroll', function () { return _this.selectionManager.refresh(); });
- this.viewportElement.addEventListener('scroll', function () { return _this.selectionManager.refresh(); });
- this.refresh(0, this.rows - 1);
- this.initGlobal();
- if (typeof focus == 'undefined') {
- var message = 'You did not pass the `focus` argument in `Terminal.prototype.open()`.\n';
- message += 'The `focus` argument now defaults to `true` but starting with xterm.js 3.0 ';
- message += 'it will default to `false`.';
- console.warn(message);
- focus = true;
- }
- if (focus) {
- this.focus();
- }
- this.bindMouse();
- this.emit('open');
-};
-Terminal.loadAddon = function (addon, callback) {
- if (typeof exports === 'object' && typeof module === 'object') {
- return require('./addons/' + addon + '/' + addon);
- }
- else if (typeof define == 'function') {
- return require(['./addons/' + addon + '/' + addon], callback);
- }
- else {
- console.error('Cannot load a module without a CommonJS or RequireJS environment.');
- return false;
- }
-};
-Terminal.prototype.updateCharSizeStyles = function () {
- this.charSizeStyleElement.textContent =
- ".xterm-wide-char{width:" + this.charMeasure.width * 2 + "px;}" +
- (".xterm-normal-char{width:" + this.charMeasure.width + "px;}") +
- (".xterm-rows > div{height:" + this.charMeasure.height + "px;}");
-};
-Terminal.prototype.bindMouse = function () {
- var el = this.element, self = this, pressed = 32;
- function sendButton(ev) {
- var button, pos;
- button = getButton(ev);
- pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
- if (!pos)
- return;
- sendEvent(button, pos);
- switch (ev.overrideType || ev.type) {
- case 'mousedown':
- pressed = button;
- break;
- case 'mouseup':
- pressed = 32;
- break;
- case 'wheel':
- break;
- }
- }
- function sendMove(ev) {
- var button = pressed, pos;
- pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
- if (!pos)
- return;
- button += 32;
- sendEvent(button, pos);
- }
- function encode(data, ch) {
- if (!self.utfMouse) {
- if (ch === 255)
- return data.push(0);
- if (ch > 127)
- ch = 127;
- data.push(ch);
- }
- else {
- if (ch === 2047)
- return data.push(0);
- if (ch < 127) {
- data.push(ch);
- }
- else {
- if (ch > 2047)
- ch = 2047;
- data.push(0xC0 | (ch >> 6));
- data.push(0x80 | (ch & 0x3F));
- }
- }
- }
- function sendEvent(button, pos) {
- if (self.vt300Mouse) {
- button &= 3;
- pos.x -= 32;
- pos.y -= 32;
- var data = EscapeSequences_1.C0.ESC + '[24';
- if (button === 0)
- data += '1';
- else if (button === 1)
- data += '3';
- else if (button === 2)
- data += '5';
- else if (button === 3)
- return;
- else
- data += '0';
- data += '~[' + pos.x + ',' + pos.y + ']\r';
- self.send(data);
- return;
- }
- if (self.decLocator) {
- button &= 3;
- pos.x -= 32;
- pos.y -= 32;
- if (button === 0)
- button = 2;
- else if (button === 1)
- button = 4;
- else if (button === 2)
- button = 6;
- else if (button === 3)
- button = 3;
- self.send(EscapeSequences_1.C0.ESC + '['
- + button
- + ';'
- + (button === 3 ? 4 : 0)
- + ';'
- + pos.y
- + ';'
- + pos.x
- + ';'
- + (pos.page || 0)
- + '&w');
- return;
- }
- if (self.urxvtMouse) {
- pos.x -= 32;
- pos.y -= 32;
- pos.x++;
- pos.y++;
- self.send(EscapeSequences_1.C0.ESC + '[' + button + ';' + pos.x + ';' + pos.y + 'M');
- return;
- }
- if (self.sgrMouse) {
- pos.x -= 32;
- pos.y -= 32;
- self.send(EscapeSequences_1.C0.ESC + '[<'
- + (((button & 3) === 3 ? button & ~3 : button) - 32)
- + ';'
- + pos.x
- + ';'
- + pos.y
- + ((button & 3) === 3 ? 'm' : 'M'));
- return;
- }
- var data = [];
- encode(data, button);
- encode(data, pos.x);
- encode(data, pos.y);
- self.send(EscapeSequences_1.C0.ESC + '[M' + String.fromCharCode.apply(String, data));
- }
- function getButton(ev) {
- var button, shift, meta, ctrl, mod;
- switch (ev.overrideType || ev.type) {
- case 'mousedown':
- button = ev.button != null
- ? +ev.button
- : ev.which != null
- ? ev.which - 1
- : null;
- if (self.browser.isMSIE) {
- button = button === 1 ? 0 : button === 4 ? 1 : button;
- }
- break;
- case 'mouseup':
- button = 3;
- break;
- case 'DOMMouseScroll':
- button = ev.detail < 0
- ? 64
- : 65;
- break;
- case 'wheel':
- button = ev.wheelDeltaY > 0
- ? 64
- : 65;
- break;
- }
- shift = ev.shiftKey ? 4 : 0;
- meta = ev.metaKey ? 8 : 0;
- ctrl = ev.ctrlKey ? 16 : 0;
- mod = shift | meta | ctrl;
- if (self.vt200Mouse) {
- mod &= ctrl;
- }
- else if (!self.normalMouse) {
- mod = 0;
- }
- button = (32 + (mod << 2)) + button;
- return button;
- }
- on(el, 'mousedown', function (ev) {
- ev.preventDefault();
- self.focus();
- if (!self.mouseEvents)
- return;
- sendButton(ev);
- if (self.vt200Mouse) {
- ev.overrideType = 'mouseup';
- sendButton(ev);
- return self.cancel(ev);
- }
- if (self.normalMouse)
- on(self.document, 'mousemove', sendMove);
- if (!self.x10Mouse) {
- on(self.document, 'mouseup', function up(ev) {
- sendButton(ev);
- if (self.normalMouse)
- off(self.document, 'mousemove', sendMove);
- off(self.document, 'mouseup', up);
- return self.cancel(ev);
- });
- }
- return self.cancel(ev);
- });
- on(el, 'wheel', function (ev) {
- if (!self.mouseEvents)
- return;
- if (self.x10Mouse
- || self.vt300Mouse
- || self.decLocator)
- return;
- sendButton(ev);
- return self.cancel(ev);
- });
- on(el, 'wheel', function (ev) {
- if (self.mouseEvents)
- return;
- self.viewport.onWheel(ev);
- return self.cancel(ev);
- });
- on(el, 'touchstart', function (ev) {
- if (self.mouseEvents)
- return;
- self.viewport.onTouchStart(ev);
- return self.cancel(ev);
- });
- on(el, 'touchmove', function (ev) {
- if (self.mouseEvents)
- return;
- self.viewport.onTouchMove(ev);
- return self.cancel(ev);
- });
-};
-Terminal.prototype.destroy = function () {
- this.readable = false;
- this.writable = false;
- this._events = {};
- this.handler = function () { };
- this.write = function () { };
- if (this.element && this.element.parentNode) {
- this.element.parentNode.removeChild(this.element);
- }
-};
-Terminal.prototype.refresh = function (start, end) {
- if (this.renderer) {
- this.renderer.queueRefresh(start, end);
- }
-};
-Terminal.prototype.queueLinkification = function (start, end) {
- if (this.linkifier) {
- for (var i = start; i <= end; i++) {
- this.linkifier.linkifyRow(i);
- }
- }
-};
-Terminal.prototype.showCursor = function () {
- if (!this.cursorState) {
- this.cursorState = 1;
- this.refresh(this.buffer.y, this.buffer.y);
- }
-};
-Terminal.prototype.scroll = function (isWrapped) {
- var row;
- if (this.buffer.lines.length === this.buffer.lines.maxLength) {
- this.buffer.lines.trimStart(1);
- this.buffer.ybase--;
- if (this.buffer.ydisp !== 0) {
- this.buffer.ydisp--;
- }
- }
- this.buffer.ybase++;
- if (!this.userScrolling) {
- this.buffer.ydisp = this.buffer.ybase;
- }
- row = this.buffer.ybase + this.rows - 1;
- row -= this.rows - 1 - this.buffer.scrollBottom;
- if (row === this.buffer.lines.length) {
- this.buffer.lines.push(this.blankLine(undefined, isWrapped));
- }
- else {
- this.buffer.lines.splice(row, 0, this.blankLine(undefined, isWrapped));
- }
- if (this.buffer.scrollTop !== 0) {
- if (this.buffer.ybase !== 0) {
- this.buffer.ybase--;
- if (!this.userScrolling) {
- this.buffer.ydisp = this.buffer.ybase;
- }
- }
- this.buffer.lines.splice(this.buffer.ybase + this.buffer.scrollTop, 1);
- }
- this.updateRange(this.buffer.scrollTop);
- this.updateRange(this.buffer.scrollBottom);
- this.emit('scroll', this.buffer.ydisp);
-};
-Terminal.prototype.scrollDisp = function (disp, suppressScrollEvent) {
- if (disp < 0) {
- if (this.buffer.ydisp === 0) {
- return;
- }
- this.userScrolling = true;
- }
- else if (disp + this.buffer.ydisp >= this.buffer.ybase) {
- this.userScrolling = false;
- }
- var oldYdisp = this.buffer.ydisp;
- this.buffer.ydisp = Math.max(Math.min(this.buffer.ydisp + disp, this.buffer.ybase), 0);
- if (oldYdisp === this.buffer.ydisp) {
- return;
- }
- if (!suppressScrollEvent) {
- this.emit('scroll', this.buffer.ydisp);
- }
- this.refresh(0, this.rows - 1);
-};
-Terminal.prototype.scrollPages = function (pageCount) {
- this.scrollDisp(pageCount * (this.rows - 1));
-};
-Terminal.prototype.scrollToTop = function () {
- this.scrollDisp(-this.buffer.ydisp);
-};
-Terminal.prototype.scrollToBottom = function () {
- this.scrollDisp(this.buffer.ybase - this.buffer.ydisp);
-};
-Terminal.prototype.write = function (data) {
- this.writeBuffer.push(data);
- if (this.options.useFlowControl && !this.xoffSentToCatchUp && this.writeBuffer.length >= WRITE_BUFFER_PAUSE_THRESHOLD) {
- this.send(EscapeSequences_1.C0.DC3);
- this.xoffSentToCatchUp = true;
- }
- if (!this.writeInProgress && this.writeBuffer.length > 0) {
- this.writeInProgress = true;
- var self = this;
- setTimeout(function () {
- self.innerWrite();
- });
- }
-};
-Terminal.prototype.innerWrite = function () {
- var writeBatch = this.writeBuffer.splice(0, WRITE_BATCH_SIZE);
- while (writeBatch.length > 0) {
- var data = writeBatch.shift();
- var l = data.length, i = 0, j, cs, ch, code, low, ch_width, row;
- if (this.xoffSentToCatchUp && writeBatch.length === 0 && this.writeBuffer.length === 0) {
- this.send(EscapeSequences_1.C0.DC1);
- this.xoffSentToCatchUp = false;
- }
- this.refreshStart = this.buffer.y;
- this.refreshEnd = this.buffer.y;
- var state = this.parser.parse(data);
- this.parser.setState(state);
- this.updateRange(this.buffer.y);
- this.refresh(this.refreshStart, this.refreshEnd);
- }
- if (this.writeBuffer.length > 0) {
- var self = this;
- setTimeout(function () {
- self.innerWrite();
- }, 0);
- }
- else {
- this.writeInProgress = false;
- }
-};
-Terminal.prototype.writeln = function (data) {
- this.write(data + '\r\n');
-};
-Terminal.prototype.attachCustomKeydownHandler = function (customKeydownHandler) {
- var message = 'attachCustomKeydownHandler() is DEPRECATED and will be removed soon. Please use attachCustomKeyEventHandler() instead.';
- console.warn(message);
- this.attachCustomKeyEventHandler(customKeydownHandler);
-};
-Terminal.prototype.attachCustomKeyEventHandler = function (customKeyEventHandler) {
- this.customKeyEventHandler = customKeyEventHandler;
-};
-Terminal.prototype.setHypertextLinkHandler = function (handler) {
- if (!this.linkifier) {
- throw new Error('Cannot attach a hypertext link handler before Terminal.open is called');
- }
- this.linkifier.setHypertextLinkHandler(handler);
- this.refresh(0, this.rows - 1);
-};
-Terminal.prototype.setHypertextValidationCallback = function (callback) {
- if (!this.linkifier) {
- throw new Error('Cannot attach a hypertext validation callback before Terminal.open is called');
- }
- this.linkifier.setHypertextValidationCallback(callback);
- this.refresh(0, this.rows - 1);
-};
-Terminal.prototype.registerLinkMatcher = function (regex, handler, options) {
- if (this.linkifier) {
- var matcherId = this.linkifier.registerLinkMatcher(regex, handler, options);
- this.refresh(0, this.rows - 1);
- return matcherId;
- }
-};
-Terminal.prototype.deregisterLinkMatcher = function (matcherId) {
- if (this.linkifier) {
- if (this.linkifier.deregisterLinkMatcher(matcherId)) {
- this.refresh(0, this.rows - 1);
- }
- }
-};
-Terminal.prototype.hasSelection = function () {
- return this.selectionManager ? this.selectionManager.hasSelection : false;
-};
-Terminal.prototype.getSelection = function () {
- return this.selectionManager ? this.selectionManager.selectionText : '';
-};
-Terminal.prototype.clearSelection = function () {
- if (this.selectionManager) {
- this.selectionManager.clearSelection();
- }
-};
-Terminal.prototype.selectAll = function () {
- if (this.selectionManager) {
- this.selectionManager.selectAll();
- }
-};
-Terminal.prototype.keyDown = function (ev) {
- if (this.customKeyEventHandler && this.customKeyEventHandler(ev) === false) {
- return false;
- }
- this.restartCursorBlinking();
- if (!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)) {
- if (this.buffer.ybase !== this.buffer.ydisp) {
- this.scrollToBottom();
- }
- return false;
- }
- var self = this;
- var result = this.evaluateKeyEscapeSequence(ev);
- if (result.key === EscapeSequences_1.C0.DC3) {
- this.writeStopped = true;
- }
- else if (result.key === EscapeSequences_1.C0.DC1) {
- this.writeStopped = false;
- }
- if (result.scrollDisp) {
- this.scrollDisp(result.scrollDisp);
- return this.cancel(ev, true);
- }
- if (isThirdLevelShift(this, ev)) {
- return true;
- }
- if (result.cancel) {
- this.cancel(ev, true);
- }
- if (!result.key) {
- return true;
- }
- this.emit('keydown', ev);
- this.emit('key', result.key, ev);
- this.showCursor();
- this.handler(result.key);
- return this.cancel(ev, true);
-};
-Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
+function evaluateKeyboardEvent(ev, applicationCursorMode, isMac, macOptionIsMeta) {
var result = {
+ type: 0,
cancel: false,
- key: undefined,
- scrollDisp: undefined
+ key: undefined
};
- var modifiers = ev.shiftKey << 0 | ev.altKey << 1 | ev.ctrlKey << 2 | ev.metaKey << 3;
+ var modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0);
switch (ev.keyCode) {
+ case 0:
+ if (ev.key === 'UIKeyInputUpArrow') {
+ if (applicationCursorMode) {
+ result.key = EscapeSequences_1.C0.ESC + 'OA';
+ }
+ else {
+ result.key = EscapeSequences_1.C0.ESC + '[A';
+ }
+ }
+ else if (ev.key === 'UIKeyInputLeftArrow') {
+ if (applicationCursorMode) {
+ result.key = EscapeSequences_1.C0.ESC + 'OD';
+ }
+ else {
+ result.key = EscapeSequences_1.C0.ESC + '[D';
+ }
+ }
+ else if (ev.key === 'UIKeyInputRightArrow') {
+ if (applicationCursorMode) {
+ result.key = EscapeSequences_1.C0.ESC + 'OC';
+ }
+ else {
+ result.key = EscapeSequences_1.C0.ESC + '[C';
+ }
+ }
+ else if (ev.key === 'UIKeyInputDownArrow') {
+ if (applicationCursorMode) {
+ result.key = EscapeSequences_1.C0.ESC + 'OB';
+ }
+ else {
+ result.key = EscapeSequences_1.C0.ESC + '[B';
+ }
+ }
+ break;
case 8:
if (ev.shiftKey) {
result.key = EscapeSequences_1.C0.BS;
break;
}
+ else if (ev.altKey) {
+ result.key = EscapeSequences_1.C0.ESC + EscapeSequences_1.C0.DEL;
+ break;
+ }
result.key = EscapeSequences_1.C0.DEL;
break;
case 9:
@@ -4514,11 +5192,11 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
case 37:
if (modifiers) {
result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'D';
- if (result.key == EscapeSequences_1.C0.ESC + '[1;3D') {
- result.key = (this.browser.isMac) ? EscapeSequences_1.C0.ESC + 'b' : EscapeSequences_1.C0.ESC + '[1;5D';
+ if (result.key === EscapeSequences_1.C0.ESC + '[1;3D') {
+ result.key = isMac ? EscapeSequences_1.C0.ESC + 'b' : EscapeSequences_1.C0.ESC + '[1;5D';
}
}
- else if (this.applicationCursor) {
+ else if (applicationCursorMode) {
result.key = EscapeSequences_1.C0.ESC + 'OD';
}
else {
@@ -4528,11 +5206,11 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
case 39:
if (modifiers) {
result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'C';
- if (result.key == EscapeSequences_1.C0.ESC + '[1;3C') {
- result.key = (this.browser.isMac) ? EscapeSequences_1.C0.ESC + 'f' : EscapeSequences_1.C0.ESC + '[1;5C';
+ if (result.key === EscapeSequences_1.C0.ESC + '[1;3C') {
+ result.key = isMac ? EscapeSequences_1.C0.ESC + 'f' : EscapeSequences_1.C0.ESC + '[1;5C';
}
}
- else if (this.applicationCursor) {
+ else if (applicationCursorMode) {
result.key = EscapeSequences_1.C0.ESC + 'OC';
}
else {
@@ -4542,11 +5220,11 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
case 38:
if (modifiers) {
result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'A';
- if (result.key == EscapeSequences_1.C0.ESC + '[1;3A') {
+ if (result.key === EscapeSequences_1.C0.ESC + '[1;3A') {
result.key = EscapeSequences_1.C0.ESC + '[1;5A';
}
}
- else if (this.applicationCursor) {
+ else if (applicationCursorMode) {
result.key = EscapeSequences_1.C0.ESC + 'OA';
}
else {
@@ -4556,11 +5234,11 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
case 40:
if (modifiers) {
result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'B';
- if (result.key == EscapeSequences_1.C0.ESC + '[1;3B') {
+ if (result.key === EscapeSequences_1.C0.ESC + '[1;3B') {
result.key = EscapeSequences_1.C0.ESC + '[1;5B';
}
}
- else if (this.applicationCursor) {
+ else if (applicationCursorMode) {
result.key = EscapeSequences_1.C0.ESC + 'OB';
}
else {
@@ -4581,24 +5259,30 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
}
break;
case 36:
- if (modifiers)
+ if (modifiers) {
result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'H';
- else if (this.applicationCursor)
+ }
+ else if (applicationCursorMode) {
result.key = EscapeSequences_1.C0.ESC + 'OH';
- else
+ }
+ else {
result.key = EscapeSequences_1.C0.ESC + '[H';
+ }
break;
case 35:
- if (modifiers)
+ if (modifiers) {
result.key = EscapeSequences_1.C0.ESC + '[1;' + (modifiers + 1) + 'F';
- else if (this.applicationCursor)
+ }
+ else if (applicationCursorMode) {
result.key = EscapeSequences_1.C0.ESC + 'OF';
- else
+ }
+ else {
result.key = EscapeSequences_1.C0.ESC + '[F';
+ }
break;
case 33:
if (ev.shiftKey) {
- result.scrollDisp = -(this.rows - 1);
+ result.type = 2;
}
else {
result.key = EscapeSequences_1.C0.ESC + '[5~';
@@ -4606,7 +5290,7 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
break;
case 34:
if (ev.shiftKey) {
- result.scrollDisp = this.rows - 1;
+ result.type = 3;
}
else {
result.key = EscapeSequences_1.C0.ESC + '[6~';
@@ -4732,401 +5416,2859 @@ Terminal.prototype.evaluateKeyEscapeSequence = function (ev) {
result.key = String.fromCharCode(29);
}
}
- else if (!this.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
- if (ev.keyCode >= 65 && ev.keyCode <= 90) {
- result.key = EscapeSequences_1.C0.ESC + String.fromCharCode(ev.keyCode + 32);
+ else if ((!isMac || macOptionIsMeta) && ev.altKey && !ev.metaKey) {
+ var keyMapping = KEYCODE_KEY_MAPPINGS[ev.keyCode];
+ var key = keyMapping && keyMapping[!ev.shiftKey ? 0 : 1];
+ if (key) {
+ result.key = EscapeSequences_1.C0.ESC + key;
}
- else if (ev.keyCode === 192) {
- result.key = EscapeSequences_1.C0.ESC + '`';
- }
- else if (ev.keyCode >= 48 && ev.keyCode <= 57) {
- result.key = EscapeSequences_1.C0.ESC + (ev.keyCode - 48);
+ else if (ev.keyCode >= 65 && ev.keyCode <= 90) {
+ var keyCode = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32;
+ result.key = EscapeSequences_1.C0.ESC + String.fromCharCode(keyCode);
}
}
- else if (this.browser.isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) {
+ else if (isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) {
if (ev.keyCode === 65) {
- this.selectAll();
+ result.type = 1;
}
}
break;
}
return result;
-};
-Terminal.prototype.setgLevel = function (g) {
- this.glevel = g;
- this.charset = this.charsets[g];
-};
-Terminal.prototype.setgCharset = function (g, charset) {
- this.charsets[g] = charset;
- if (this.glevel === g) {
- this.charset = charset;
- }
-};
-Terminal.prototype.keyPress = function (ev) {
- var key;
- if (this.customKeyEventHandler && this.customKeyEventHandler(ev) === false) {
- return false;
- }
- this.cancel(ev);
- if (ev.charCode) {
- key = ev.charCode;
- }
- else if (ev.which == null) {
- key = ev.keyCode;
- }
- else if (ev.which !== 0 && ev.charCode !== 0) {
- key = ev.which;
- }
- else {
- return false;
- }
- if (!key || ((ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this, ev))) {
- return false;
- }
- key = String.fromCharCode(key);
- this.emit('keypress', key, ev);
- this.emit('key', key, ev);
- this.showCursor();
- this.handler(key);
- return true;
-};
-Terminal.prototype.send = function (data) {
- var self = this;
- if (!this.queue) {
- setTimeout(function () {
- self.handler(self.queue);
- self.queue = '';
- }, 1);
- }
- this.queue += data;
-};
-Terminal.prototype.bell = function () {
- if (!this.visualBell)
- return;
- var self = this;
- this.element.style.borderColor = 'white';
- setTimeout(function () {
- self.element.style.borderColor = '';
- }, 10);
- if (this.popOnBell)
- this.focus();
-};
-Terminal.prototype.log = function () {
- if (!this.debug)
- return;
- if (!this.context.console || !this.context.console.log)
- return;
- var args = Array.prototype.slice.call(arguments);
- this.context.console.log.apply(this.context.console, args);
-};
-Terminal.prototype.error = function () {
- if (!this.debug)
- return;
- if (!this.context.console || !this.context.console.error)
- return;
- var args = Array.prototype.slice.call(arguments);
- this.context.console.error.apply(this.context.console, args);
-};
-Terminal.prototype.resize = function (x, y) {
- if (isNaN(x) || isNaN(y)) {
- return;
- }
- if (y > this.getOption('scrollback')) {
- this.setOption('scrollback', y);
- }
- var line, el, i, j, ch, addToY;
- if (x === this.cols && y === this.rows) {
- if (!this.charMeasure.width || !this.charMeasure.height) {
- this.charMeasure.measure();
- }
- return;
- }
- if (x < 1)
- x = 1;
- if (y < 1)
- y = 1;
- this.buffers.resize(x, y);
- while (this.children.length < y) {
- this.insertRow();
- }
- while (this.children.length > y) {
- el = this.children.shift();
- if (!el)
- continue;
- el.parentNode.removeChild(el);
- }
- this.cols = x;
- this.rows = y;
- this.setupStops(this.cols);
- this.charMeasure.measure();
- this.refresh(0, this.rows - 1);
- this.geometry = [this.cols, this.rows];
- this.emit('resize', { terminal: this, cols: x, rows: y });
-};
-Terminal.prototype.updateRange = function (y) {
- if (y < this.refreshStart)
- this.refreshStart = y;
- if (y > this.refreshEnd)
- this.refreshEnd = y;
-};
-Terminal.prototype.maxRange = function () {
- this.refreshStart = 0;
- this.refreshEnd = this.rows - 1;
-};
-Terminal.prototype.setupStops = function (i) {
- if (i != null) {
- if (!this.buffer.tabs[i]) {
- i = this.prevStop(i);
- }
- }
- else {
- this.buffer.tabs = {};
- i = 0;
- }
- for (; i < this.cols; i += this.getOption('tabStopWidth')) {
- this.buffer.tabs[i] = true;
- }
-};
-Terminal.prototype.prevStop = function (x) {
- if (x == null)
- x = this.buffer.x;
- while (!this.buffer.tabs[--x] && x > 0)
- ;
- return x >= this.cols
- ? this.cols - 1
- : x < 0 ? 0 : x;
-};
-Terminal.prototype.nextStop = function (x) {
- if (x == null)
- x = this.buffer.x;
- while (!this.buffer.tabs[++x] && x < this.cols)
- ;
- return x >= this.cols
- ? this.cols - 1
- : x < 0 ? 0 : x;
-};
-Terminal.prototype.eraseRight = function (x, y) {
- var line = this.buffer.lines.get(this.buffer.ybase + y);
- if (!line) {
- return;
- }
- var ch = [this.eraseAttr(), ' ', 1];
- for (; x < this.cols; x++) {
- line[x] = ch;
- }
- this.updateRange(y);
-};
-Terminal.prototype.eraseLeft = function (x, y) {
- var line = this.buffer.lines.get(this.buffer.ybase + y);
- if (!line) {
- return;
- }
- var ch = [this.eraseAttr(), ' ', 1];
- x++;
- while (x--) {
- line[x] = ch;
- }
- this.updateRange(y);
-};
-Terminal.prototype.clear = function () {
- if (this.buffer.ybase === 0 && this.buffer.y === 0) {
- return;
- }
- this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y));
- this.buffer.lines.length = 1;
- this.buffer.ydisp = 0;
- this.buffer.ybase = 0;
- this.buffer.y = 0;
- for (var i = 1; i < this.rows; i++) {
- this.buffer.lines.push(this.blankLine());
- }
- this.refresh(0, this.rows - 1);
- this.emit('scroll', this.buffer.ydisp);
-};
-Terminal.prototype.eraseLine = function (y) {
- this.eraseRight(0, y);
-};
-Terminal.prototype.blankLine = function (cur, isWrapped, cols) {
- var attr = cur
- ? this.eraseAttr()
- : this.defAttr;
- var ch = [attr, ' ', 1], line = [], i = 0;
- if (isWrapped) {
- line.isWrapped = isWrapped;
- }
- cols = cols || this.cols;
- for (; i < cols; i++) {
- line[i] = ch;
- }
- return line;
-};
-Terminal.prototype.ch = function (cur) {
- return cur
- ? [this.eraseAttr(), ' ', 1]
- : [this.defAttr, ' ', 1];
-};
-Terminal.prototype.is = function (term) {
- var name = this.termName;
- return (name + '').indexOf(term) === 0;
-};
-Terminal.prototype.handler = function (data) {
- if (this.options.disableStdin) {
- return;
- }
- if (this.selectionManager && this.selectionManager.hasSelection) {
- this.selectionManager.clearSelection();
- }
- if (this.buffer.ybase !== this.buffer.ydisp) {
- this.scrollToBottom();
- }
- this.emit('data', data);
-};
-Terminal.prototype.handleTitle = function (title) {
- this.emit('title', title);
-};
-Terminal.prototype.index = function () {
- this.buffer.y++;
- if (this.buffer.y > this.buffer.scrollBottom) {
- this.buffer.y--;
- this.scroll();
- }
- if (this.buffer.x >= this.cols) {
- this.buffer.x--;
- }
-};
-Terminal.prototype.reverseIndex = function () {
- var j;
- if (this.buffer.y === this.buffer.scrollTop) {
- this.buffer.lines.shiftElements(this.buffer.y + this.buffer.ybase, this.rows - 1, 1);
- this.buffer.lines.set(this.buffer.y + this.buffer.ybase, this.blankLine(true));
- this.updateRange(this.buffer.scrollTop);
- this.updateRange(this.buffer.scrollBottom);
- }
- else {
- this.buffer.y--;
- }
-};
-Terminal.prototype.reset = function () {
- this.options.rows = this.rows;
- this.options.cols = this.cols;
- var customKeyEventHandler = this.customKeyEventHandler;
- var cursorBlinkInterval = this.cursorBlinkInterval;
- var inputHandler = this.inputHandler;
- Terminal.call(this, this.options);
- this.customKeyEventHandler = customKeyEventHandler;
- this.cursorBlinkInterval = cursorBlinkInterval;
- this.inputHandler = inputHandler;
- this.refresh(0, this.rows - 1);
- this.viewport.syncScrollArea();
-};
-Terminal.prototype.tabSet = function () {
- this.buffer.tabs[this.buffer.x] = true;
-};
-function on(el, type, handler, capture) {
- if (!Array.isArray(el)) {
- el = [el];
- }
- el.forEach(function (element) {
- element.addEventListener(type, handler, capture || false);
- });
}
-function off(el, type, handler, capture) {
- el.removeEventListener(type, handler, capture || false);
+exports.evaluateKeyboardEvent = evaluateKeyboardEvent;
+
+},{"../../common/data/EscapeSequences":18}],21:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var EscapeSequences_1 = require("../common/data/EscapeSequences");
+var AltClickHandler = (function () {
+ function AltClickHandler(_mouseEvent, _terminal) {
+ this._mouseEvent = _mouseEvent;
+ this._terminal = _terminal;
+ this._lines = this._terminal.buffer.lines;
+ this._startCol = this._terminal.buffer.x;
+ this._startRow = this._terminal.buffer.y;
+ var coordinates = this._terminal.mouseHelper.getCoords(this._mouseEvent, this._terminal.element, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, false);
+ if (coordinates) {
+ _a = coordinates.map(function (coordinate) {
+ return coordinate - 1;
+ }), this._endCol = _a[0], this._endRow = _a[1];
+ }
+ var _a;
+ }
+ AltClickHandler.prototype.move = function () {
+ if (this._mouseEvent.altKey && this._endCol !== undefined && this._endRow !== undefined) {
+ this._terminal.send(this._arrowSequences());
+ }
+ };
+ AltClickHandler.prototype._arrowSequences = function () {
+ if (!this._terminal.buffer.hasScrollback) {
+ return this._resetStartingRow() + this._moveToRequestedRow() + this._moveToRequestedCol();
+ }
+ return this._moveHorizontallyOnly();
+ };
+ AltClickHandler.prototype._resetStartingRow = function () {
+ if (this._moveToRequestedRow().length === 0) {
+ return '';
+ }
+ return repeat(this._bufferLine(this._startCol, this._startRow, this._startCol, this._startRow - this._wrappedRowsForRow(this._startRow), false).length, this._sequence("D"));
+ };
+ AltClickHandler.prototype._moveToRequestedRow = function () {
+ var startRow = this._startRow - this._wrappedRowsForRow(this._startRow);
+ var endRow = this._endRow - this._wrappedRowsForRow(this._endRow);
+ var rowsToMove = Math.abs(startRow - endRow) - this._wrappedRowsCount();
+ return repeat(rowsToMove, this._sequence(this._verticalDirection()));
+ };
+ AltClickHandler.prototype._moveToRequestedCol = function () {
+ var startRow;
+ if (this._moveToRequestedRow().length > 0) {
+ startRow = this._endRow - this._wrappedRowsForRow(this._endRow);
+ }
+ else {
+ startRow = this._startRow;
+ }
+ var endRow = this._endRow;
+ var direction = this._horizontalDirection();
+ return repeat(this._bufferLine(this._startCol, startRow, this._endCol, endRow, direction === "C").length, this._sequence(direction));
+ };
+ AltClickHandler.prototype._moveHorizontallyOnly = function () {
+ var direction = this._horizontalDirection();
+ return repeat(Math.abs(this._startCol - this._endCol), this._sequence(direction));
+ };
+ AltClickHandler.prototype._wrappedRowsCount = function () {
+ var wrappedRows = 0;
+ var startRow = this._startRow - this._wrappedRowsForRow(this._startRow);
+ var endRow = this._endRow - this._wrappedRowsForRow(this._endRow);
+ for (var i = 0; i < Math.abs(startRow - endRow); i++) {
+ var direction = this._verticalDirection() === "A" ? -1 : 1;
+ if (this._lines.get(startRow + (direction * i)).isWrapped) {
+ wrappedRows++;
+ }
+ }
+ return wrappedRows;
+ };
+ AltClickHandler.prototype._wrappedRowsForRow = function (currentRow) {
+ var rowCount = 0;
+ var lineWraps = this._lines.get(currentRow).isWrapped;
+ while (lineWraps && currentRow >= 0 && currentRow < this._terminal.rows) {
+ rowCount++;
+ currentRow--;
+ lineWraps = this._lines.get(currentRow).isWrapped;
+ }
+ return rowCount;
+ };
+ AltClickHandler.prototype._horizontalDirection = function () {
+ var startRow;
+ if (this._moveToRequestedRow().length > 0) {
+ startRow = this._endRow - this._wrappedRowsForRow(this._endRow);
+ }
+ else {
+ startRow = this._startRow;
+ }
+ if ((this._startCol < this._endCol &&
+ startRow <= this._endRow) ||
+ (this._startCol >= this._endCol &&
+ startRow < this._endRow)) {
+ return "C";
+ }
+ return "D";
+ };
+ AltClickHandler.prototype._verticalDirection = function () {
+ if (this._startRow > this._endRow) {
+ return "A";
+ }
+ return "B";
+ };
+ AltClickHandler.prototype._bufferLine = function (startCol, startRow, endCol, endRow, forward) {
+ var currentCol = startCol;
+ var currentRow = startRow;
+ var bufferStr = '';
+ while (currentCol !== endCol || currentRow !== endRow) {
+ currentCol += forward ? 1 : -1;
+ if (forward && currentCol > this._terminal.cols - 1) {
+ bufferStr += this._terminal.buffer.translateBufferLineToString(currentRow, false, startCol, currentCol);
+ currentCol = 0;
+ startCol = 0;
+ currentRow++;
+ }
+ else if (!forward && currentCol < 0) {
+ bufferStr += this._terminal.buffer.translateBufferLineToString(currentRow, false, 0, startCol + 1);
+ currentCol = this._terminal.cols - 1;
+ startCol = currentCol;
+ currentRow--;
+ }
+ }
+ return bufferStr + this._terminal.buffer.translateBufferLineToString(currentRow, false, startCol, currentCol);
+ };
+ AltClickHandler.prototype._sequence = function (direction) {
+ var mod = this._terminal.applicationCursor ? 'O' : '[';
+ return EscapeSequences_1.C0.ESC + mod + direction;
+ };
+ return AltClickHandler;
+}());
+exports.AltClickHandler = AltClickHandler;
+function repeat(count, str) {
+ count = Math.floor(count);
+ var rpt = '';
+ for (var i = 0; i < count; i++) {
+ rpt += str;
+ }
+ return rpt;
}
-function cancel(ev, force) {
- if (!this.cancelEvents && !force) {
- return;
+
+},{"../common/data/EscapeSequences":18}],22:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+function prepareTextForTerminal(text) {
+ return text.replace(/\r?\n/g, '\r');
+}
+exports.prepareTextForTerminal = prepareTextForTerminal;
+function bracketTextForPaste(text, bracketedPasteMode) {
+ if (bracketedPasteMode) {
+ return '\x1b[200~' + text + '\x1b[201~';
+ }
+ return text;
+}
+exports.bracketTextForPaste = bracketTextForPaste;
+function copyHandler(ev, term, selectionManager) {
+ if (term.browser.isMSIE) {
+ window.clipboardData.setData('Text', selectionManager.selectionText);
+ }
+ else {
+ ev.clipboardData.setData('text/plain', selectionManager.selectionText);
}
ev.preventDefault();
+}
+exports.copyHandler = copyHandler;
+function pasteHandler(ev, term) {
ev.stopPropagation();
- return false;
-}
-function inherits(child, parent) {
- function f() {
- this.constructor = child;
+ var text;
+ var dispatchPaste = function (text) {
+ text = prepareTextForTerminal(text);
+ text = bracketTextForPaste(text, term.bracketedPasteMode);
+ term.handler(text);
+ term.textarea.value = '';
+ term.emit('paste', text);
+ term.cancel(ev);
+ };
+ if (term.browser.isMSIE) {
+ if (window.clipboardData) {
+ text = window.clipboardData.getData('Text');
+ dispatchPaste(text);
+ }
}
- f.prototype = parent.prototype;
- child.prototype = new f;
-}
-function indexOf(obj, el) {
- var i = obj.length;
- while (i--) {
- if (obj[i] === el)
- return i;
+ else {
+ if (ev.clipboardData) {
+ text = ev.clipboardData.getData('text/plain');
+ dispatchPaste(text);
+ }
}
- return -1;
}
-function isThirdLevelShift(term, ev) {
- var thirdLevelKey = (term.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
- (term.browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
- if (ev.type == 'keypress') {
- return thirdLevelKey;
- }
- return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
+exports.pasteHandler = pasteHandler;
+function moveTextAreaUnderMouseCursor(ev, textarea) {
+ textarea.style.position = 'fixed';
+ textarea.style.width = '20px';
+ textarea.style.height = '20px';
+ textarea.style.left = (ev.clientX - 10) + 'px';
+ textarea.style.top = (ev.clientY - 10) + 'px';
+ textarea.style.zIndex = '1000';
+ textarea.focus();
+ setTimeout(function () {
+ textarea.style.position = null;
+ textarea.style.width = null;
+ textarea.style.height = null;
+ textarea.style.left = null;
+ textarea.style.top = null;
+ textarea.style.zIndex = null;
+ }, 200);
}
-Terminal.prototype.matchColor = matchColor;
-function matchColor(r1, g1, b1) {
- var hash = (r1 << 16) | (g1 << 8) | b1;
- if (matchColor._cache[hash] != null) {
- return matchColor._cache[hash];
+exports.moveTextAreaUnderMouseCursor = moveTextAreaUnderMouseCursor;
+function rightClickHandler(ev, textarea, selectionManager, shouldSelectWord) {
+ moveTextAreaUnderMouseCursor(ev, textarea);
+ if (shouldSelectWord && !selectionManager.isClickInSelection(ev)) {
+ selectionManager.selectWordAtCursor(ev);
}
- 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;
+ textarea.value = selectionManager.selectionText;
+ textarea.select();
+}
+exports.rightClickHandler = rightClickHandler;
+
+},{}],23:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Terminal_1 = require("../Terminal");
+var Strings = require("../Strings");
+var Terminal = (function () {
+ function Terminal(options) {
+ this._core = new Terminal_1.Terminal(options);
+ }
+ Object.defineProperty(Terminal.prototype, "element", {
+ get: function () { return this._core.element; },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Terminal.prototype, "textarea", {
+ get: function () { return this._core.textarea; },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Terminal.prototype, "rows", {
+ get: function () { return this._core.rows; },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Terminal.prototype, "cols", {
+ get: function () { return this._core.cols; },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(Terminal.prototype, "markers", {
+ get: function () { return this._core.markers; },
+ enumerable: true,
+ configurable: true
+ });
+ Terminal.prototype.blur = function () {
+ this._core.blur();
+ };
+ Terminal.prototype.focus = function () {
+ this._core.focus();
+ };
+ Terminal.prototype.on = function (type, listener) {
+ this._core.on(type, listener);
+ };
+ Terminal.prototype.off = function (type, listener) {
+ this._core.off(type, listener);
+ };
+ Terminal.prototype.emit = function (type, data) {
+ this._core.emit(type, data);
+ };
+ Terminal.prototype.addDisposableListener = function (type, handler) {
+ return this._core.addDisposableListener(type, handler);
+ };
+ Terminal.prototype.resize = function (columns, rows) {
+ this._core.resize(columns, rows);
+ };
+ Terminal.prototype.writeln = function (data) {
+ this._core.writeln(data);
+ };
+ Terminal.prototype.open = function (parent) {
+ this._core.open(parent);
+ };
+ Terminal.prototype.attachCustomKeyEventHandler = function (customKeyEventHandler) {
+ this._core.attachCustomKeyEventHandler(customKeyEventHandler);
+ };
+ Terminal.prototype.registerLinkMatcher = function (regex, handler, options) {
+ return this._core.registerLinkMatcher(regex, handler, options);
+ };
+ Terminal.prototype.deregisterLinkMatcher = function (matcherId) {
+ this._core.deregisterLinkMatcher(matcherId);
+ };
+ Terminal.prototype.addMarker = function (cursorYOffset) {
+ return this._core.addMarker(cursorYOffset);
+ };
+ Terminal.prototype.hasSelection = function () {
+ return this._core.hasSelection();
+ };
+ Terminal.prototype.getSelection = function () {
+ return this._core.getSelection();
+ };
+ Terminal.prototype.clearSelection = function () {
+ this._core.clearSelection();
+ };
+ Terminal.prototype.selectAll = function () {
+ this._core.selectAll();
+ };
+ Terminal.prototype.selectLines = function (start, end) {
+ this._core.selectLines(start, end);
+ };
+ Terminal.prototype.dispose = function () {
+ this._core.dispose();
+ };
+ Terminal.prototype.destroy = function () {
+ this._core.destroy();
+ };
+ Terminal.prototype.scrollLines = function (amount) {
+ this._core.scrollLines(amount);
+ };
+ Terminal.prototype.scrollPages = function (pageCount) {
+ this._core.scrollPages(pageCount);
+ };
+ Terminal.prototype.scrollToTop = function () {
+ this._core.scrollToTop();
+ };
+ Terminal.prototype.scrollToBottom = function () {
+ this._core.scrollToBottom();
+ };
+ Terminal.prototype.scrollToLine = function (line) {
+ this._core.scrollToLine(line);
+ };
+ Terminal.prototype.clear = function () {
+ this._core.clear();
+ };
+ Terminal.prototype.write = function (data) {
+ this._core.write(data);
+ };
+ Terminal.prototype.getOption = function (key) {
+ return this._core.getOption(key);
+ };
+ Terminal.prototype.setOption = function (key, value) {
+ this._core.setOption(key, value);
+ };
+ Terminal.prototype.refresh = function (start, end) {
+ this._core.refresh(start, end);
+ };
+ Terminal.prototype.reset = function () {
+ this._core.reset();
+ };
+ Terminal.applyAddon = function (addon) {
+ addon.apply(Terminal);
+ };
+ Object.defineProperty(Terminal, "strings", {
+ get: function () {
+ return Strings;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ return Terminal;
+}());
+exports.Terminal = Terminal;
+
+},{"../Strings":13,"../Terminal":14}],24:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Types_1 = require("./atlas/Types");
+var CharAtlasCache_1 = require("./atlas/CharAtlasCache");
+var Buffer_1 = require("../Buffer");
+var BaseRenderLayer = (function () {
+ function BaseRenderLayer(_container, id, zIndex, _alpha, _colors) {
+ this._container = _container;
+ this._alpha = _alpha;
+ this._colors = _colors;
+ this._scaledCharWidth = 0;
+ this._scaledCharHeight = 0;
+ this._scaledCellWidth = 0;
+ this._scaledCellHeight = 0;
+ this._scaledCharLeft = 0;
+ this._scaledCharTop = 0;
+ this._canvas = document.createElement('canvas');
+ this._canvas.classList.add("xterm-" + id + "-layer");
+ this._canvas.style.zIndex = zIndex.toString();
+ this._initCanvas();
+ this._container.appendChild(this._canvas);
+ }
+ BaseRenderLayer.prototype._initCanvas = function () {
+ this._ctx = this._canvas.getContext('2d', { alpha: this._alpha });
+ if (!this._alpha) {
+ this.clearAll();
+ }
+ };
+ BaseRenderLayer.prototype.onOptionsChanged = function (terminal) { };
+ BaseRenderLayer.prototype.onBlur = function (terminal) { };
+ BaseRenderLayer.prototype.onFocus = function (terminal) { };
+ BaseRenderLayer.prototype.onCursorMove = function (terminal) { };
+ BaseRenderLayer.prototype.onGridChanged = function (terminal, startRow, endRow) { };
+ BaseRenderLayer.prototype.onSelectionChanged = function (terminal, start, end, columnSelectMode) {
+ if (columnSelectMode === void 0) { columnSelectMode = false; }
+ };
+ BaseRenderLayer.prototype.onThemeChanged = function (terminal, colorSet) {
+ this._refreshCharAtlas(terminal, colorSet);
+ };
+ BaseRenderLayer.prototype.setTransparency = function (terminal, alpha) {
+ if (alpha === this._alpha) {
+ return;
+ }
+ var oldCanvas = this._canvas;
+ this._alpha = alpha;
+ this._canvas = this._canvas.cloneNode();
+ this._initCanvas();
+ this._container.replaceChild(this._canvas, oldCanvas);
+ this._refreshCharAtlas(terminal, this._colors);
+ this.onGridChanged(terminal, 0, terminal.rows - 1);
+ };
+ BaseRenderLayer.prototype._refreshCharAtlas = function (terminal, colorSet) {
+ if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) {
+ return;
+ }
+ this._charAtlas = CharAtlasCache_1.acquireCharAtlas(terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight);
+ this._charAtlas.warmUp();
+ };
+ BaseRenderLayer.prototype.resize = function (terminal, dim) {
+ this._scaledCellWidth = dim.scaledCellWidth;
+ this._scaledCellHeight = dim.scaledCellHeight;
+ this._scaledCharWidth = dim.scaledCharWidth;
+ this._scaledCharHeight = dim.scaledCharHeight;
+ this._scaledCharLeft = dim.scaledCharLeft;
+ this._scaledCharTop = dim.scaledCharTop;
+ this._canvas.width = dim.scaledCanvasWidth;
+ this._canvas.height = dim.scaledCanvasHeight;
+ this._canvas.style.width = dim.canvasWidth + "px";
+ this._canvas.style.height = dim.canvasHeight + "px";
+ if (!this._alpha) {
+ this.clearAll();
+ }
+ this._refreshCharAtlas(terminal, this._colors);
+ };
+ BaseRenderLayer.prototype.fillCells = function (x, y, width, height) {
+ this._ctx.fillRect(x * this._scaledCellWidth, y * this._scaledCellHeight, width * this._scaledCellWidth, height * this._scaledCellHeight);
+ };
+ BaseRenderLayer.prototype.fillBottomLineAtCells = function (x, y, width) {
+ if (width === void 0) { width = 1; }
+ this._ctx.fillRect(x * this._scaledCellWidth, (y + 1) * this._scaledCellHeight - window.devicePixelRatio - 1, width * this._scaledCellWidth, window.devicePixelRatio);
+ };
+ BaseRenderLayer.prototype.fillLeftLineAtCell = function (x, y) {
+ this._ctx.fillRect(x * this._scaledCellWidth, y * this._scaledCellHeight, window.devicePixelRatio, this._scaledCellHeight);
+ };
+ BaseRenderLayer.prototype.strokeRectAtCell = function (x, y, width, height) {
+ this._ctx.lineWidth = window.devicePixelRatio;
+ this._ctx.strokeRect(x * this._scaledCellWidth + window.devicePixelRatio / 2, y * this._scaledCellHeight + (window.devicePixelRatio / 2), width * this._scaledCellWidth - window.devicePixelRatio, (height * this._scaledCellHeight) - window.devicePixelRatio);
+ };
+ BaseRenderLayer.prototype.clearAll = function () {
+ if (this._alpha) {
+ this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
+ }
+ else {
+ this._ctx.fillStyle = this._colors.background.css;
+ this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
+ }
+ };
+ BaseRenderLayer.prototype.clearCells = function (x, y, width, height) {
+ if (this._alpha) {
+ this._ctx.clearRect(x * this._scaledCellWidth, y * this._scaledCellHeight, width * this._scaledCellWidth, height * this._scaledCellHeight);
+ }
+ else {
+ this._ctx.fillStyle = this._colors.background.css;
+ this._ctx.fillRect(x * this._scaledCellWidth, y * this._scaledCellHeight, width * this._scaledCellWidth, height * this._scaledCellHeight);
+ }
+ };
+ BaseRenderLayer.prototype.fillCharTrueColor = function (terminal, charData, x, y) {
+ this._ctx.font = this._getFont(terminal, false, false);
+ this._ctx.textBaseline = 'top';
+ this._clipRow(terminal, y);
+ this._ctx.fillText(charData[Buffer_1.CHAR_DATA_CHAR_INDEX], x * this._scaledCellWidth + this._scaledCharLeft, y * this._scaledCellHeight + this._scaledCharTop);
+ };
+ BaseRenderLayer.prototype.drawChar = function (terminal, char, code, width, x, y, fg, bg, bold, dim, italic) {
+ var drawInBrightColor = terminal.options.drawBoldTextInBrightColors && bold && fg < 8;
+ fg += drawInBrightColor ? 8 : 0;
+ var atlasDidDraw = this._charAtlas && this._charAtlas.draw(this._ctx, { char: char, code: code, bg: bg, fg: fg, bold: bold && terminal.options.enableBold, dim: dim, italic: italic }, x * this._scaledCellWidth + this._scaledCharLeft, y * this._scaledCellHeight + this._scaledCharTop);
+ if (!atlasDidDraw) {
+ this._drawUncachedChar(terminal, char, width, fg, x, y, bold && terminal.options.enableBold, dim, italic);
+ }
+ };
+ BaseRenderLayer.prototype._drawUncachedChar = function (terminal, char, width, fg, x, y, bold, dim, italic) {
+ this._ctx.save();
+ this._ctx.font = this._getFont(terminal, bold, italic);
+ this._ctx.textBaseline = 'top';
+ if (fg === Types_1.INVERTED_DEFAULT_COLOR) {
+ this._ctx.fillStyle = this._colors.background.css;
+ }
+ else if (fg < 256) {
+ this._ctx.fillStyle = this._colors.ansi[fg].css;
+ }
+ else {
+ this._ctx.fillStyle = this._colors.foreground.css;
+ }
+ this._clipRow(terminal, y);
+ if (dim) {
+ this._ctx.globalAlpha = Types_1.DIM_OPACITY;
+ }
+ this._ctx.fillText(char, x * this._scaledCellWidth + this._scaledCharLeft, y * this._scaledCellHeight + this._scaledCharTop);
+ this._ctx.restore();
+ };
+ BaseRenderLayer.prototype._clipRow = function (terminal, y) {
+ this._ctx.beginPath();
+ this._ctx.rect(0, y * this._scaledCellHeight, terminal.cols * this._scaledCellWidth, this._scaledCellHeight);
+ this._ctx.clip();
+ };
+ BaseRenderLayer.prototype._getFont = function (terminal, isBold, isItalic) {
+ var fontWeight = isBold ? terminal.options.fontWeightBold : terminal.options.fontWeight;
+ var fontStyle = isItalic ? 'italic' : '';
+ return fontStyle + " " + fontWeight + " " + terminal.options.fontSize * window.devicePixelRatio + "px " + terminal.options.fontFamily;
+ };
+ return BaseRenderLayer;
+}());
+exports.BaseRenderLayer = BaseRenderLayer;
+
+},{"../Buffer":2,"./atlas/CharAtlasCache":33,"./atlas/Types":39}],25:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var DEFAULT_FOREGROUND = fromHex('#ffffff');
+var DEFAULT_BACKGROUND = fromHex('#000000');
+var DEFAULT_CURSOR = fromHex('#ffffff');
+var DEFAULT_CURSOR_ACCENT = fromHex('#000000');
+var DEFAULT_SELECTION = {
+ css: 'rgba(255, 255, 255, 0.3)',
+ rgba: 0xFFFFFF77
+};
+exports.DEFAULT_ANSI_COLORS = (function () {
+ var colors = [
+ fromHex('#2e3436'),
+ fromHex('#cc0000'),
+ fromHex('#4e9a06'),
+ fromHex('#c4a000'),
+ fromHex('#3465a4'),
+ fromHex('#75507b'),
+ fromHex('#06989a'),
+ fromHex('#d3d7cf'),
+ fromHex('#555753'),
+ fromHex('#ef2929'),
+ fromHex('#8ae234'),
+ fromHex('#fce94f'),
+ fromHex('#729fcf'),
+ fromHex('#ad7fa8'),
+ fromHex('#34e2e2'),
+ fromHex('#eeeeec')
+ ];
+ var v = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff];
+ for (var i = 0; i < 216; i++) {
+ var r = v[(i / 36) % 6 | 0];
+ var g = v[(i / 6) % 6 | 0];
+ var b = v[i % 6];
+ colors.push({
+ css: "#" + toPaddedHex(r) + toPaddedHex(g) + toPaddedHex(b),
+ rgba: ((r << 24) | (g << 16) | (b << 8) | 0xFF) >>> 0
+ });
+ }
+ for (var i = 0; i < 24; i++) {
+ var c = 8 + i * 10;
+ var ch = toPaddedHex(c);
+ colors.push({
+ css: "#" + ch + ch + ch,
+ rgba: ((c << 24) | (c << 16) | (c << 8) | 0xFF) >>> 0
+ });
+ }
+ return colors;
+})();
+function fromHex(css) {
+ return {
+ css: css,
+ rgba: parseInt(css.slice(1), 16) << 8 | 0xFF
+ };
+}
+function toPaddedHex(c) {
+ var s = c.toString(16);
+ return s.length < 2 ? '0' + s : s;
+}
+var ColorManager = (function () {
+ function ColorManager(document, allowTransparency) {
+ this.allowTransparency = allowTransparency;
+ var canvas = document.createElement('canvas');
+ canvas.width = 1;
+ canvas.height = 1;
+ this._ctx = canvas.getContext('2d');
+ this._ctx.globalCompositeOperation = 'copy';
+ this._litmusColor = this._ctx.createLinearGradient(0, 0, 1, 1);
+ this.colors = {
+ foreground: DEFAULT_FOREGROUND,
+ background: DEFAULT_BACKGROUND,
+ cursor: DEFAULT_CURSOR,
+ cursorAccent: DEFAULT_CURSOR_ACCENT,
+ selection: DEFAULT_SELECTION,
+ ansi: exports.DEFAULT_ANSI_COLORS.slice()
+ };
+ }
+ ColorManager.prototype.setTheme = function (theme) {
+ this.colors.foreground = this._parseColor(theme.foreground, DEFAULT_FOREGROUND);
+ this.colors.background = this._parseColor(theme.background, DEFAULT_BACKGROUND);
+ this.colors.cursor = this._parseColor(theme.cursor, DEFAULT_CURSOR, true);
+ this.colors.cursorAccent = this._parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT, true);
+ this.colors.selection = this._parseColor(theme.selection, DEFAULT_SELECTION, true);
+ this.colors.ansi[0] = this._parseColor(theme.black, exports.DEFAULT_ANSI_COLORS[0]);
+ this.colors.ansi[1] = this._parseColor(theme.red, exports.DEFAULT_ANSI_COLORS[1]);
+ this.colors.ansi[2] = this._parseColor(theme.green, exports.DEFAULT_ANSI_COLORS[2]);
+ this.colors.ansi[3] = this._parseColor(theme.yellow, exports.DEFAULT_ANSI_COLORS[3]);
+ this.colors.ansi[4] = this._parseColor(theme.blue, exports.DEFAULT_ANSI_COLORS[4]);
+ this.colors.ansi[5] = this._parseColor(theme.magenta, exports.DEFAULT_ANSI_COLORS[5]);
+ this.colors.ansi[6] = this._parseColor(theme.cyan, exports.DEFAULT_ANSI_COLORS[6]);
+ this.colors.ansi[7] = this._parseColor(theme.white, exports.DEFAULT_ANSI_COLORS[7]);
+ this.colors.ansi[8] = this._parseColor(theme.brightBlack, exports.DEFAULT_ANSI_COLORS[8]);
+ this.colors.ansi[9] = this._parseColor(theme.brightRed, exports.DEFAULT_ANSI_COLORS[9]);
+ this.colors.ansi[10] = this._parseColor(theme.brightGreen, exports.DEFAULT_ANSI_COLORS[10]);
+ this.colors.ansi[11] = this._parseColor(theme.brightYellow, exports.DEFAULT_ANSI_COLORS[11]);
+ this.colors.ansi[12] = this._parseColor(theme.brightBlue, exports.DEFAULT_ANSI_COLORS[12]);
+ this.colors.ansi[13] = this._parseColor(theme.brightMagenta, exports.DEFAULT_ANSI_COLORS[13]);
+ this.colors.ansi[14] = this._parseColor(theme.brightCyan, exports.DEFAULT_ANSI_COLORS[14]);
+ this.colors.ansi[15] = this._parseColor(theme.brightWhite, exports.DEFAULT_ANSI_COLORS[15]);
+ };
+ ColorManager.prototype._parseColor = function (css, fallback, allowTransparency) {
+ if (allowTransparency === void 0) { allowTransparency = this.allowTransparency; }
+ if (!css) {
+ return fallback;
+ }
+ this._ctx.fillStyle = this._litmusColor;
+ this._ctx.fillStyle = css;
+ if (typeof this._ctx.fillStyle !== 'string') {
+ console.warn("Color: " + css + " is invalid using fallback " + fallback.css);
+ return fallback;
+ }
+ this._ctx.fillRect(0, 0, 1, 1);
+ var data = this._ctx.getImageData(0, 0, 1, 1).data;
+ if (!allowTransparency && data[3] !== 0xFF) {
+ console.warn("Color: " + css + " is using transparency, but allowTransparency is false. " +
+ ("Using fallback " + fallback.css + "."));
+ return fallback;
+ }
+ return {
+ css: css,
+ rgba: (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]) >>> 0
+ };
+ };
+ return ColorManager;
+}());
+exports.ColorManager = ColorManager;
+
+},{}],26:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Buffer_1 = require("../Buffer");
+var BaseRenderLayer_1 = require("./BaseRenderLayer");
+var BLINK_INTERVAL = 600;
+var CursorRenderLayer = (function (_super) {
+ __extends(CursorRenderLayer, _super);
+ function CursorRenderLayer(container, zIndex, colors) {
+ var _this = _super.call(this, container, 'cursor', zIndex, true, colors) || this;
+ _this._state = {
+ x: null,
+ y: null,
+ isFocused: null,
+ style: null,
+ width: null
+ };
+ _this._cursorRenderers = {
+ 'bar': _this._renderBarCursor.bind(_this),
+ 'block': _this._renderBlockCursor.bind(_this),
+ 'underline': _this._renderUnderlineCursor.bind(_this)
+ };
+ return _this;
+ }
+ CursorRenderLayer.prototype.resize = function (terminal, dim) {
+ _super.prototype.resize.call(this, terminal, dim);
+ this._state = {
+ x: null,
+ y: null,
+ isFocused: null,
+ style: null,
+ width: null
+ };
+ };
+ CursorRenderLayer.prototype.reset = function (terminal) {
+ this._clearCursor();
+ if (this._cursorBlinkStateManager) {
+ this._cursorBlinkStateManager.dispose();
+ this._cursorBlinkStateManager = null;
+ this.onOptionsChanged(terminal);
+ }
+ };
+ CursorRenderLayer.prototype.onBlur = function (terminal) {
+ if (this._cursorBlinkStateManager) {
+ this._cursorBlinkStateManager.pause();
+ }
+ terminal.refresh(terminal.buffer.y, terminal.buffer.y);
+ };
+ CursorRenderLayer.prototype.onFocus = function (terminal) {
+ if (this._cursorBlinkStateManager) {
+ this._cursorBlinkStateManager.resume(terminal);
+ }
+ else {
+ terminal.refresh(terminal.buffer.y, terminal.buffer.y);
+ }
+ };
+ CursorRenderLayer.prototype.onOptionsChanged = function (terminal) {
+ var _this = this;
+ if (terminal.options.cursorBlink) {
+ if (!this._cursorBlinkStateManager) {
+ this._cursorBlinkStateManager = new CursorBlinkStateManager(terminal, function () {
+ _this._render(terminal, true);
+ });
+ }
+ }
+ else {
+ if (this._cursorBlinkStateManager) {
+ this._cursorBlinkStateManager.dispose();
+ this._cursorBlinkStateManager = null;
+ }
+ terminal.refresh(terminal.buffer.y, terminal.buffer.y);
+ }
+ };
+ CursorRenderLayer.prototype.onCursorMove = function (terminal) {
+ if (this._cursorBlinkStateManager) {
+ this._cursorBlinkStateManager.restartBlinkAnimation(terminal);
+ }
+ };
+ CursorRenderLayer.prototype.onGridChanged = function (terminal, startRow, endRow) {
+ if (!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isPaused) {
+ this._render(terminal, false);
+ }
+ else {
+ this._cursorBlinkStateManager.restartBlinkAnimation(terminal);
+ }
+ };
+ CursorRenderLayer.prototype._render = function (terminal, triggeredByAnimationFrame) {
+ if (!terminal.cursorState || terminal.cursorHidden) {
+ this._clearCursor();
+ return;
+ }
+ var cursorY = terminal.buffer.ybase + terminal.buffer.y;
+ var viewportRelativeCursorY = cursorY - terminal.buffer.ydisp;
+ if (viewportRelativeCursorY < 0 || viewportRelativeCursorY >= terminal.rows) {
+ this._clearCursor();
+ return;
+ }
+ var charData = terminal.buffer.lines.get(cursorY)[terminal.buffer.x];
+ if (!charData) {
+ return;
+ }
+ if (!terminal.isFocused) {
+ this._clearCursor();
+ this._ctx.save();
+ this._ctx.fillStyle = this._colors.cursor.css;
+ this._renderBlurCursor(terminal, terminal.buffer.x, viewportRelativeCursorY, charData);
+ this._ctx.restore();
+ this._state.x = terminal.buffer.x;
+ this._state.y = viewportRelativeCursorY;
+ this._state.isFocused = false;
+ this._state.style = terminal.options.cursorStyle;
+ this._state.width = charData[Buffer_1.CHAR_DATA_WIDTH_INDEX];
+ return;
+ }
+ if (this._cursorBlinkStateManager && !this._cursorBlinkStateManager.isCursorVisible) {
+ this._clearCursor();
+ return;
+ }
+ if (this._state) {
+ if (this._state.x === terminal.buffer.x &&
+ this._state.y === viewportRelativeCursorY &&
+ this._state.isFocused === terminal.isFocused &&
+ this._state.style === terminal.options.cursorStyle &&
+ this._state.width === charData[Buffer_1.CHAR_DATA_WIDTH_INDEX]) {
+ return;
+ }
+ this._clearCursor();
+ }
+ this._ctx.save();
+ this._cursorRenderers[terminal.options.cursorStyle || 'block'](terminal, terminal.buffer.x, viewportRelativeCursorY, charData);
+ this._ctx.restore();
+ this._state.x = terminal.buffer.x;
+ this._state.y = viewportRelativeCursorY;
+ this._state.isFocused = false;
+ this._state.style = terminal.options.cursorStyle;
+ this._state.width = charData[Buffer_1.CHAR_DATA_WIDTH_INDEX];
+ };
+ CursorRenderLayer.prototype._clearCursor = function () {
+ if (this._state) {
+ this.clearCells(this._state.x, this._state.y, this._state.width, 1);
+ this._state = {
+ x: null,
+ y: null,
+ isFocused: null,
+ style: null,
+ width: null
+ };
+ }
+ };
+ CursorRenderLayer.prototype._renderBarCursor = function (terminal, x, y, charData) {
+ this._ctx.save();
+ this._ctx.fillStyle = this._colors.cursor.css;
+ this.fillLeftLineAtCell(x, y);
+ this._ctx.restore();
+ };
+ CursorRenderLayer.prototype._renderBlockCursor = function (terminal, x, y, charData) {
+ this._ctx.save();
+ this._ctx.fillStyle = this._colors.cursor.css;
+ this.fillCells(x, y, charData[Buffer_1.CHAR_DATA_WIDTH_INDEX], 1);
+ this._ctx.fillStyle = this._colors.cursorAccent.css;
+ this.fillCharTrueColor(terminal, charData, x, y);
+ this._ctx.restore();
+ };
+ CursorRenderLayer.prototype._renderUnderlineCursor = function (terminal, x, y, charData) {
+ this._ctx.save();
+ this._ctx.fillStyle = this._colors.cursor.css;
+ this.fillBottomLineAtCells(x, y);
+ this._ctx.restore();
+ };
+ CursorRenderLayer.prototype._renderBlurCursor = function (terminal, x, y, charData) {
+ this._ctx.save();
+ this._ctx.strokeStyle = this._colors.cursor.css;
+ this.strokeRectAtCell(x, y, charData[Buffer_1.CHAR_DATA_WIDTH_INDEX], 1);
+ this._ctx.restore();
+ };
+ return CursorRenderLayer;
+}(BaseRenderLayer_1.BaseRenderLayer));
+exports.CursorRenderLayer = CursorRenderLayer;
+var CursorBlinkStateManager = (function () {
+ function CursorBlinkStateManager(terminal, _renderCallback) {
+ this._renderCallback = _renderCallback;
+ this.isCursorVisible = true;
+ if (terminal.isFocused) {
+ this._restartInterval();
+ }
+ }
+ Object.defineProperty(CursorBlinkStateManager.prototype, "isPaused", {
+ get: function () { return !(this._blinkStartTimeout || this._blinkInterval); },
+ enumerable: true,
+ configurable: true
+ });
+ CursorBlinkStateManager.prototype.dispose = function () {
+ if (this._blinkInterval) {
+ window.clearInterval(this._blinkInterval);
+ this._blinkInterval = null;
+ }
+ if (this._blinkStartTimeout) {
+ window.clearTimeout(this._blinkStartTimeout);
+ this._blinkStartTimeout = null;
+ }
+ if (this._animationFrame) {
+ window.cancelAnimationFrame(this._animationFrame);
+ this._animationFrame = null;
+ }
+ };
+ CursorBlinkStateManager.prototype.restartBlinkAnimation = function (terminal) {
+ var _this = this;
+ if (this.isPaused) {
+ return;
+ }
+ this._animationTimeRestarted = Date.now();
+ this.isCursorVisible = true;
+ if (!this._animationFrame) {
+ this._animationFrame = window.requestAnimationFrame(function () {
+ _this._renderCallback();
+ _this._animationFrame = null;
+ });
+ }
+ };
+ CursorBlinkStateManager.prototype._restartInterval = function (timeToStart) {
+ var _this = this;
+ if (timeToStart === void 0) { timeToStart = BLINK_INTERVAL; }
+ if (this._blinkInterval) {
+ window.clearInterval(this._blinkInterval);
+ }
+ this._blinkStartTimeout = setTimeout(function () {
+ if (_this._animationTimeRestarted) {
+ var time = BLINK_INTERVAL - (Date.now() - _this._animationTimeRestarted);
+ _this._animationTimeRestarted = null;
+ if (time > 0) {
+ _this._restartInterval(time);
+ return;
+ }
+ }
+ _this.isCursorVisible = false;
+ _this._animationFrame = window.requestAnimationFrame(function () {
+ _this._renderCallback();
+ _this._animationFrame = null;
+ });
+ _this._blinkInterval = setInterval(function () {
+ if (_this._animationTimeRestarted) {
+ var time = BLINK_INTERVAL - (Date.now() - _this._animationTimeRestarted);
+ _this._animationTimeRestarted = null;
+ _this._restartInterval(time);
+ return;
+ }
+ _this.isCursorVisible = !_this.isCursorVisible;
+ _this._animationFrame = window.requestAnimationFrame(function () {
+ _this._renderCallback();
+ _this._animationFrame = null;
+ });
+ }, BLINK_INTERVAL);
+ }, timeToStart);
+ };
+ CursorBlinkStateManager.prototype.pause = function () {
+ this.isCursorVisible = true;
+ if (this._blinkInterval) {
+ window.clearInterval(this._blinkInterval);
+ this._blinkInterval = null;
+ }
+ if (this._blinkStartTimeout) {
+ window.clearTimeout(this._blinkStartTimeout);
+ this._blinkStartTimeout = null;
+ }
+ if (this._animationFrame) {
+ window.cancelAnimationFrame(this._animationFrame);
+ this._animationFrame = null;
+ }
+ };
+ CursorBlinkStateManager.prototype.resume = function (terminal) {
+ this._animationTimeRestarted = null;
+ this._restartInterval();
+ this.restartBlinkAnimation(terminal);
+ };
+ return CursorBlinkStateManager;
+}());
+
+},{"../Buffer":2,"./BaseRenderLayer":24}],27:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var GridCache = (function () {
+ function GridCache() {
+ this.cache = [];
+ }
+ GridCache.prototype.resize = function (width, height) {
+ for (var x = 0; x < width; x++) {
+ if (this.cache.length <= x) {
+ this.cache.push([]);
+ }
+ for (var y = this.cache[x].length; y < height; y++) {
+ this.cache[x].push(null);
+ }
+ this.cache[x].length = height;
+ }
+ this.cache.length = width;
+ };
+ GridCache.prototype.clear = function () {
+ for (var x = 0; x < this.cache.length; x++) {
+ for (var y = 0; y < this.cache[x].length; y++) {
+ this.cache[x][y] = null;
+ }
+ }
+ };
+ return GridCache;
+}());
+exports.GridCache = GridCache;
+
+},{}],28:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var BaseRenderLayer_1 = require("./BaseRenderLayer");
+var LinkRenderLayer = (function (_super) {
+ __extends(LinkRenderLayer, _super);
+ function LinkRenderLayer(container, zIndex, colors, terminal) {
+ var _this = _super.call(this, container, 'link', zIndex, true, colors) || this;
+ _this._state = null;
+ terminal.linkifier.on("linkhover", function (e) { return _this._onLinkHover(e); });
+ terminal.linkifier.on("linkleave", function (e) { return _this._onLinkLeave(e); });
+ return _this;
+ }
+ LinkRenderLayer.prototype.resize = function (terminal, dim) {
+ _super.prototype.resize.call(this, terminal, dim);
+ this._state = null;
+ };
+ LinkRenderLayer.prototype.reset = function (terminal) {
+ this._clearCurrentLink();
+ };
+ LinkRenderLayer.prototype._clearCurrentLink = function () {
+ if (this._state) {
+ this.clearCells(this._state.x1, this._state.y1, this._state.cols - this._state.x1, 1);
+ var middleRowCount = this._state.y2 - this._state.y1 - 1;
+ if (middleRowCount > 0) {
+ this.clearCells(0, this._state.y1 + 1, this._state.cols, middleRowCount);
+ }
+ this.clearCells(0, this._state.y2, this._state.x2, 1);
+ this._state = null;
+ }
+ };
+ LinkRenderLayer.prototype._onLinkHover = function (e) {
+ this._ctx.fillStyle = this._colors.foreground.css;
+ if (e.y1 === e.y2) {
+ this.fillBottomLineAtCells(e.x1, e.y1, e.x2 - e.x1);
+ }
+ else {
+ this.fillBottomLineAtCells(e.x1, e.y1, e.cols - e.x1);
+ for (var y = e.y1 + 1; y < e.y2; y++) {
+ this.fillBottomLineAtCells(0, y, e.cols);
+ }
+ this.fillBottomLineAtCells(0, e.y2, e.x2);
+ }
+ this._state = e;
+ };
+ LinkRenderLayer.prototype._onLinkLeave = function (e) {
+ this._clearCurrentLink();
+ };
+ return LinkRenderLayer;
+}(BaseRenderLayer_1.BaseRenderLayer));
+exports.LinkRenderLayer = LinkRenderLayer;
+
+},{"./BaseRenderLayer":24}],29:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var TextRenderLayer_1 = require("./TextRenderLayer");
+var SelectionRenderLayer_1 = require("./SelectionRenderLayer");
+var CursorRenderLayer_1 = require("./CursorRenderLayer");
+var ColorManager_1 = require("./ColorManager");
+var LinkRenderLayer_1 = require("./LinkRenderLayer");
+var EventEmitter_1 = require("../EventEmitter");
+var RenderDebouncer_1 = require("../ui/RenderDebouncer");
+var ScreenDprMonitor_1 = require("../ui/ScreenDprMonitor");
+var Renderer = (function (_super) {
+ __extends(Renderer, _super);
+ function Renderer(_terminal, theme) {
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._isPaused = false;
+ _this._needsFullRefresh = false;
+ var allowTransparency = _this._terminal.options.allowTransparency;
+ _this.colorManager = new ColorManager_1.ColorManager(document, allowTransparency);
+ if (theme) {
+ _this.colorManager.setTheme(theme);
+ }
+ _this._renderLayers = [
+ new TextRenderLayer_1.TextRenderLayer(_this._terminal.screenElement, 0, _this.colorManager.colors, allowTransparency),
+ new SelectionRenderLayer_1.SelectionRenderLayer(_this._terminal.screenElement, 1, _this.colorManager.colors),
+ new LinkRenderLayer_1.LinkRenderLayer(_this._terminal.screenElement, 2, _this.colorManager.colors, _this._terminal),
+ new CursorRenderLayer_1.CursorRenderLayer(_this._terminal.screenElement, 3, _this.colorManager.colors)
+ ];
+ _this.dimensions = {
+ scaledCharWidth: null,
+ scaledCharHeight: null,
+ scaledCellWidth: null,
+ scaledCellHeight: null,
+ scaledCharLeft: null,
+ scaledCharTop: null,
+ scaledCanvasWidth: null,
+ scaledCanvasHeight: null,
+ canvasWidth: null,
+ canvasHeight: null,
+ actualCellWidth: null,
+ actualCellHeight: null
+ };
+ _this._devicePixelRatio = window.devicePixelRatio;
+ _this._updateDimensions();
+ _this.onOptionsChanged();
+ _this._renderDebouncer = new RenderDebouncer_1.RenderDebouncer(_this._terminal, _this._renderRows.bind(_this));
+ _this._screenDprMonitor = new ScreenDprMonitor_1.ScreenDprMonitor();
+ _this._screenDprMonitor.setListener(function () { return _this.onWindowResize(window.devicePixelRatio); });
+ _this.register(_this._screenDprMonitor);
+ if ('IntersectionObserver' in window) {
+ var observer_1 = new IntersectionObserver(function (e) { return _this.onIntersectionChange(e[0]); }, { threshold: 0 });
+ observer_1.observe(_this._terminal.element);
+ _this.register({ dispose: function () { return observer_1.disconnect(); } });
+ }
+ return _this;
+ }
+ Renderer.prototype.onIntersectionChange = function (entry) {
+ this._isPaused = entry.intersectionRatio === 0;
+ if (!this._isPaused && this._needsFullRefresh) {
+ this._terminal.refresh(0, this._terminal.rows - 1);
+ }
+ };
+ Renderer.prototype.onWindowResize = function (devicePixelRatio) {
+ if (this._devicePixelRatio !== devicePixelRatio) {
+ this._devicePixelRatio = devicePixelRatio;
+ this.onResize(this._terminal.cols, this._terminal.rows);
+ }
+ };
+ Renderer.prototype.setTheme = function (theme) {
+ var _this = this;
+ this.colorManager.setTheme(theme);
+ this._renderLayers.forEach(function (l) {
+ l.onThemeChanged(_this._terminal, _this.colorManager.colors);
+ l.reset(_this._terminal);
+ });
+ if (this._isPaused) {
+ this._needsFullRefresh = true;
+ }
+ else {
+ this._terminal.refresh(0, this._terminal.rows - 1);
+ }
+ return this.colorManager.colors;
+ };
+ Renderer.prototype.onResize = function (cols, rows) {
+ var _this = this;
+ this._updateDimensions();
+ this._renderLayers.forEach(function (l) { return l.resize(_this._terminal, _this.dimensions); });
+ if (this._isPaused) {
+ this._needsFullRefresh = true;
+ }
+ else {
+ this._terminal.refresh(0, this._terminal.rows - 1);
+ }
+ this._terminal.screenElement.style.width = this.dimensions.canvasWidth + "px";
+ this._terminal.screenElement.style.height = this.dimensions.canvasHeight + "px";
+ this.emit('resize', {
+ width: this.dimensions.canvasWidth,
+ height: this.dimensions.canvasHeight
+ });
+ };
+ Renderer.prototype.onCharSizeChanged = function () {
+ this.onResize(this._terminal.cols, this._terminal.rows);
+ };
+ Renderer.prototype.onBlur = function () {
+ var _this = this;
+ this._runOperation(function (l) { return l.onBlur(_this._terminal); });
+ };
+ Renderer.prototype.onFocus = function () {
+ var _this = this;
+ this._runOperation(function (l) { return l.onFocus(_this._terminal); });
+ };
+ Renderer.prototype.onSelectionChanged = function (start, end, columnSelectMode) {
+ var _this = this;
+ if (columnSelectMode === void 0) { columnSelectMode = false; }
+ this._runOperation(function (l) { return l.onSelectionChanged(_this._terminal, start, end, columnSelectMode); });
+ };
+ Renderer.prototype.onCursorMove = function () {
+ var _this = this;
+ this._runOperation(function (l) { return l.onCursorMove(_this._terminal); });
+ };
+ Renderer.prototype.onOptionsChanged = function () {
+ var _this = this;
+ this.colorManager.allowTransparency = this._terminal.options.allowTransparency;
+ this._runOperation(function (l) { return l.onOptionsChanged(_this._terminal); });
+ };
+ Renderer.prototype.clear = function () {
+ var _this = this;
+ this._runOperation(function (l) { return l.reset(_this._terminal); });
+ };
+ Renderer.prototype._runOperation = function (operation) {
+ if (this._isPaused) {
+ this._needsFullRefresh = true;
+ }
+ else {
+ this._renderLayers.forEach(function (l) { return operation(l); });
+ }
+ };
+ Renderer.prototype.refreshRows = function (start, end) {
+ if (this._isPaused) {
+ this._needsFullRefresh = true;
+ return;
+ }
+ this._renderDebouncer.refresh(start, end);
+ };
+ Renderer.prototype._renderRows = function (start, end) {
+ var _this = this;
+ this._renderLayers.forEach(function (l) { return l.onGridChanged(_this._terminal, start, end); });
+ this._terminal.emit('refresh', { start: start, end: end });
+ };
+ Renderer.prototype._updateDimensions = function () {
+ if (!this._terminal.charMeasure.width || !this._terminal.charMeasure.height) {
+ return;
+ }
+ this.dimensions.scaledCharWidth = Math.floor(this._terminal.charMeasure.width * window.devicePixelRatio);
+ this.dimensions.scaledCharHeight = Math.ceil(this._terminal.charMeasure.height * window.devicePixelRatio);
+ this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight);
+ this.dimensions.scaledCharTop = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2);
+ this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing);
+ this.dimensions.scaledCharLeft = Math.floor(this._terminal.options.letterSpacing / 2);
+ this.dimensions.scaledCanvasHeight = this._terminal.rows * this.dimensions.scaledCellHeight;
+ this.dimensions.scaledCanvasWidth = this._terminal.cols * this.dimensions.scaledCellWidth;
+ this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / window.devicePixelRatio);
+ this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / window.devicePixelRatio);
+ this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._terminal.rows;
+ this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._terminal.cols;
+ };
+ return Renderer;
+}(EventEmitter_1.EventEmitter));
+exports.Renderer = Renderer;
+
+},{"../EventEmitter":7,"../ui/RenderDebouncer":48,"../ui/ScreenDprMonitor":49,"./ColorManager":25,"./CursorRenderLayer":26,"./LinkRenderLayer":28,"./SelectionRenderLayer":30,"./TextRenderLayer":31}],30:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var BaseRenderLayer_1 = require("./BaseRenderLayer");
+var SelectionRenderLayer = (function (_super) {
+ __extends(SelectionRenderLayer, _super);
+ function SelectionRenderLayer(container, zIndex, colors) {
+ var _this = _super.call(this, container, 'selection', zIndex, true, colors) || this;
+ _this._clearState();
+ return _this;
+ }
+ SelectionRenderLayer.prototype._clearState = function () {
+ this._state = {
+ start: null,
+ end: null,
+ columnSelectMode: null,
+ ydisp: null
+ };
+ };
+ SelectionRenderLayer.prototype.resize = function (terminal, dim) {
+ _super.prototype.resize.call(this, terminal, dim);
+ this._clearState();
+ };
+ SelectionRenderLayer.prototype.reset = function (terminal) {
+ if (this._state.start && this._state.end) {
+ this._clearState();
+ this.clearAll();
+ }
+ };
+ SelectionRenderLayer.prototype.onSelectionChanged = function (terminal, start, end, columnSelectMode) {
+ if (!this._didStateChange(start, end, columnSelectMode, terminal.buffer.ydisp)) {
+ return;
+ }
+ this.clearAll();
+ if (!start || !end) {
+ return;
+ }
+ var viewportStartRow = start[1] - terminal.buffer.ydisp;
+ var viewportEndRow = end[1] - terminal.buffer.ydisp;
+ var viewportCappedStartRow = Math.max(viewportStartRow, 0);
+ var viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1);
+ if (viewportCappedStartRow >= terminal.rows || viewportCappedEndRow < 0) {
+ return;
+ }
+ this._ctx.fillStyle = this._colors.selection.css;
+ if (columnSelectMode) {
+ var startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
+ var width = end[0] - startCol;
+ var height = viewportCappedEndRow - viewportCappedStartRow + 1;
+ this.fillCells(startCol, viewportCappedStartRow, width, height);
+ }
+ else {
+ var startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
+ var startRowEndCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : terminal.cols;
+ this.fillCells(startCol, viewportCappedStartRow, startRowEndCol - startCol, 1);
+ var middleRowsCount = Math.max(viewportCappedEndRow - viewportCappedStartRow - 1, 0);
+ this.fillCells(0, viewportCappedStartRow + 1, terminal.cols, middleRowsCount);
+ if (viewportCappedStartRow !== viewportCappedEndRow) {
+ var endCol = viewportEndRow === viewportCappedEndRow ? end[0] : terminal.cols;
+ this.fillCells(0, viewportCappedEndRow, endCol, 1);
+ }
+ }
+ this._state.start = [start[0], start[1]];
+ this._state.end = [end[0], end[1]];
+ this._state.columnSelectMode = columnSelectMode;
+ this._state.ydisp = terminal.buffer.ydisp;
+ };
+ SelectionRenderLayer.prototype._didStateChange = function (start, end, columnSelectMode, ydisp) {
+ return !this._areCoordinatesEqual(start, this._state.start) ||
+ !this._areCoordinatesEqual(end, this._state.end) ||
+ columnSelectMode !== this._state.columnSelectMode ||
+ ydisp !== this._state.ydisp;
+ };
+ SelectionRenderLayer.prototype._areCoordinatesEqual = function (coord1, coord2) {
+ if (!coord1 || !coord2) {
+ return false;
+ }
+ return coord1[0] === coord2[0] && coord1[1] === coord2[1];
+ };
+ return SelectionRenderLayer;
+}(BaseRenderLayer_1.BaseRenderLayer));
+exports.SelectionRenderLayer = SelectionRenderLayer;
+
+},{"./BaseRenderLayer":24}],31:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Buffer_1 = require("../Buffer");
+var Types_1 = require("./atlas/Types");
+var GridCache_1 = require("./GridCache");
+var BaseRenderLayer_1 = require("./BaseRenderLayer");
+var TextRenderLayer = (function (_super) {
+ __extends(TextRenderLayer, _super);
+ function TextRenderLayer(container, zIndex, colors, alpha) {
+ var _this = _super.call(this, container, 'text', zIndex, alpha, colors) || this;
+ _this._characterOverlapCache = {};
+ _this._state = new GridCache_1.GridCache();
+ return _this;
+ }
+ TextRenderLayer.prototype.resize = function (terminal, dim) {
+ _super.prototype.resize.call(this, terminal, dim);
+ var terminalFont = this._getFont(terminal, false, false);
+ if (this._characterWidth !== dim.scaledCharWidth || this._characterFont !== terminalFont) {
+ this._characterWidth = dim.scaledCharWidth;
+ this._characterFont = terminalFont;
+ this._characterOverlapCache = {};
+ }
+ this._state.clear();
+ this._state.resize(terminal.cols, terminal.rows);
+ };
+ TextRenderLayer.prototype.reset = function (terminal) {
+ this._state.clear();
+ this.clearAll();
+ };
+ TextRenderLayer.prototype._forEachCell = function (terminal, firstRow, lastRow, callback) {
+ for (var y = firstRow; y <= lastRow; y++) {
+ var row = y + terminal.buffer.ydisp;
+ var line = terminal.buffer.lines.get(row);
+ for (var x = 0; x < terminal.cols; x++) {
+ var charData = line[x];
+ var code = charData[Buffer_1.CHAR_DATA_CODE_INDEX];
+ var char = charData[Buffer_1.CHAR_DATA_CHAR_INDEX];
+ var attr = charData[Buffer_1.CHAR_DATA_ATTR_INDEX];
+ var width = charData[Buffer_1.CHAR_DATA_WIDTH_INDEX];
+ if (width === 0) {
+ continue;
+ }
+ if (this._isOverlapping(charData)) {
+ if (x < line.length - 1 && line[x + 1][Buffer_1.CHAR_DATA_CODE_INDEX] === 32) {
+ width = 2;
+ }
+ }
+ var flags = attr >> 18;
+ var bg = attr & 0x1ff;
+ var fg = (attr >> 9) & 0x1ff;
+ if (flags & 8) {
+ var temp = bg;
+ bg = fg;
+ fg = temp;
+ if (fg === 256) {
+ fg = Types_1.INVERTED_DEFAULT_COLOR;
+ }
+ if (bg === 257) {
+ bg = Types_1.INVERTED_DEFAULT_COLOR;
+ }
+ }
+ callback(code, char, width, x, y, fg, bg, flags);
+ }
+ }
+ };
+ TextRenderLayer.prototype._drawBackground = function (terminal, firstRow, lastRow) {
+ var _this = this;
+ var ctx = this._ctx;
+ var cols = terminal.cols;
+ var startX = 0;
+ var startY = 0;
+ var prevFillStyle = null;
+ ctx.save();
+ this._forEachCell(terminal, firstRow, lastRow, function (code, char, width, x, y, fg, bg, flags) {
+ var nextFillStyle = null;
+ if (bg === Types_1.INVERTED_DEFAULT_COLOR) {
+ nextFillStyle = _this._colors.foreground.css;
+ }
+ else if (bg < 256) {
+ nextFillStyle = _this._colors.ansi[bg].css;
+ }
+ if (prevFillStyle === null) {
+ startX = x;
+ startY = y;
+ }
+ if (y !== startY) {
+ ctx.fillStyle = prevFillStyle;
+ _this.fillCells(startX, startY, cols - startX, 1);
+ startX = x;
+ startY = y;
+ }
+ else if (prevFillStyle !== nextFillStyle) {
+ ctx.fillStyle = prevFillStyle;
+ _this.fillCells(startX, startY, x - startX, 1);
+ startX = x;
+ startY = y;
+ }
+ prevFillStyle = nextFillStyle;
+ });
+ if (prevFillStyle !== null) {
+ ctx.fillStyle = prevFillStyle;
+ this.fillCells(startX, startY, cols - startX, 1);
+ }
+ ctx.restore();
+ };
+ TextRenderLayer.prototype._drawForeground = function (terminal, firstRow, lastRow) {
+ var _this = this;
+ this._forEachCell(terminal, firstRow, lastRow, function (code, char, width, x, y, fg, bg, flags) {
+ if (flags & 16) {
+ return;
+ }
+ if (flags & 2) {
+ _this._ctx.save();
+ if (fg === Types_1.INVERTED_DEFAULT_COLOR) {
+ _this._ctx.fillStyle = _this._colors.background.css;
+ }
+ else if (fg < 256) {
+ _this._ctx.fillStyle = _this._colors.ansi[fg].css;
+ }
+ else {
+ _this._ctx.fillStyle = _this._colors.foreground.css;
+ }
+ _this.fillBottomLineAtCells(x, y);
+ _this._ctx.restore();
+ }
+ _this.drawChar(terminal, char, code, width, x, y, fg, bg, !!(flags & 1), !!(flags & 32), !!(flags & 64));
+ });
+ };
+ TextRenderLayer.prototype.onGridChanged = function (terminal, firstRow, lastRow) {
+ if (this._state.cache.length === 0) {
+ return;
+ }
+ if (this._charAtlas) {
+ this._charAtlas.beginFrame();
+ }
+ this.clearCells(0, firstRow, terminal.cols, lastRow - firstRow + 1);
+ this._drawBackground(terminal, firstRow, lastRow);
+ this._drawForeground(terminal, firstRow, lastRow);
+ };
+ TextRenderLayer.prototype.onOptionsChanged = function (terminal) {
+ this.setTransparency(terminal, terminal.options.allowTransparency);
+ };
+ TextRenderLayer.prototype._isOverlapping = function (charData) {
+ if (charData[Buffer_1.CHAR_DATA_WIDTH_INDEX] !== 1) {
+ return false;
+ }
+ var code = charData[Buffer_1.CHAR_DATA_CODE_INDEX];
+ if (code < 256) {
+ return false;
+ }
+ var char = charData[Buffer_1.CHAR_DATA_CHAR_INDEX];
+ if (this._characterOverlapCache.hasOwnProperty(char)) {
+ return this._characterOverlapCache[char];
+ }
+ this._ctx.save();
+ this._ctx.font = this._characterFont;
+ var overlaps = Math.floor(this._ctx.measureText(char).width) > this._characterWidth;
+ this._ctx.restore();
+ this._characterOverlapCache[char] = overlaps;
+ return overlaps;
+ };
+ return TextRenderLayer;
+}(BaseRenderLayer_1.BaseRenderLayer));
+exports.TextRenderLayer = TextRenderLayer;
+
+},{"../Buffer":2,"./BaseRenderLayer":24,"./GridCache":27,"./atlas/Types":39}],32:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var BaseCharAtlas = (function () {
+ function BaseCharAtlas() {
+ this._didWarmUp = false;
+ }
+ BaseCharAtlas.prototype.warmUp = function () {
+ if (!this._didWarmUp) {
+ this._doWarmUp();
+ this._didWarmUp = true;
+ }
+ };
+ BaseCharAtlas.prototype._doWarmUp = function () { };
+ BaseCharAtlas.prototype.beginFrame = function () { };
+ return BaseCharAtlas;
+}());
+exports.default = BaseCharAtlas;
+
+},{}],33:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var CharAtlasUtils_1 = require("./CharAtlasUtils");
+var DynamicCharAtlas_1 = require("./DynamicCharAtlas");
+var NoneCharAtlas_1 = require("./NoneCharAtlas");
+var StaticCharAtlas_1 = require("./StaticCharAtlas");
+var charAtlasImplementations = {
+ 'none': NoneCharAtlas_1.default,
+ 'static': StaticCharAtlas_1.default,
+ 'dynamic': DynamicCharAtlas_1.default
+};
+var charAtlasCache = [];
+function acquireCharAtlas(terminal, colors, scaledCharWidth, scaledCharHeight) {
+ var newConfig = CharAtlasUtils_1.generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors);
+ for (var i = 0; i < charAtlasCache.length; i++) {
+ var entry = charAtlasCache[i];
+ var ownedByIndex = entry.ownedBy.indexOf(terminal);
+ if (ownedByIndex >= 0) {
+ if (CharAtlasUtils_1.configEquals(entry.config, newConfig)) {
+ return entry.atlas;
+ }
+ if (entry.ownedBy.length === 1) {
+ charAtlasCache.splice(i, 1);
+ }
+ else {
+ entry.ownedBy.splice(ownedByIndex, 1);
+ }
break;
}
- if (diff < ldiff) {
- ldiff = diff;
- li = i;
+ }
+ for (var i = 0; i < charAtlasCache.length; i++) {
+ var entry = charAtlasCache[i];
+ if (CharAtlasUtils_1.configEquals(entry.config, newConfig)) {
+ entry.ownedBy.push(terminal);
+ return entry.atlas;
}
}
- return matchColor._cache[hash] = li;
+ var newEntry = {
+ atlas: new charAtlasImplementations[terminal.options.experimentalCharAtlas](document, newConfig),
+ config: newConfig,
+ ownedBy: [terminal]
+ };
+ charAtlasCache.push(newEntry);
+ return newEntry.atlas;
}
-matchColor._cache = {};
-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);
+exports.acquireCharAtlas = acquireCharAtlas;
+function removeTerminalFromCache(terminal) {
+ for (var i = 0; i < charAtlasCache.length; i++) {
+ var index = charAtlasCache[i].ownedBy.indexOf(terminal);
+ if (index !== -1) {
+ if (charAtlasCache[i].ownedBy.length === 1) {
+ charAtlasCache.splice(i, 1);
+ }
+ else {
+ charAtlasCache[i].ownedBy.splice(index, 1);
+ }
+ break;
+ }
+ }
+}
+exports.removeTerminalFromCache = removeTerminalFromCache;
+
+},{"./CharAtlasUtils":34,"./DynamicCharAtlas":35,"./NoneCharAtlas":37,"./StaticCharAtlas":38}],34:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+function generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors) {
+ var clonedColors = {
+ foreground: colors.foreground,
+ background: colors.background,
+ cursor: null,
+ cursorAccent: null,
+ selection: null,
+ ansi: colors.ansi.slice(0, 16)
+ };
+ return {
+ type: terminal.options.experimentalCharAtlas,
+ devicePixelRatio: window.devicePixelRatio,
+ scaledCharWidth: scaledCharWidth,
+ scaledCharHeight: scaledCharHeight,
+ fontFamily: terminal.options.fontFamily,
+ fontSize: terminal.options.fontSize,
+ fontWeight: terminal.options.fontWeight,
+ fontWeightBold: terminal.options.fontWeightBold,
+ allowTransparency: terminal.options.allowTransparency,
+ colors: clonedColors
+ };
+}
+exports.generateConfig = generateConfig;
+function configEquals(a, b) {
+ for (var i = 0; i < a.colors.ansi.length; i++) {
+ if (a.colors.ansi[i].rgba !== b.colors.ansi[i].rgba) {
+ return false;
+ }
+ }
+ return a.type === b.type &&
+ a.devicePixelRatio === b.devicePixelRatio &&
+ a.fontFamily === b.fontFamily &&
+ a.fontSize === b.fontSize &&
+ a.fontWeight === b.fontWeight &&
+ a.fontWeightBold === b.fontWeightBold &&
+ a.allowTransparency === b.allowTransparency &&
+ a.scaledCharWidth === b.scaledCharWidth &&
+ a.scaledCharHeight === b.scaledCharHeight &&
+ a.colors.foreground === b.colors.foreground &&
+ a.colors.background === b.colors.background;
+}
+exports.configEquals = configEquals;
+
+},{}],35:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Types_1 = require("./Types");
+var BaseCharAtlas_1 = require("./BaseCharAtlas");
+var ColorManager_1 = require("../ColorManager");
+var CharAtlasGenerator_1 = require("../../shared/atlas/CharAtlasGenerator");
+var LRUMap_1 = require("./LRUMap");
+var TEXTURE_WIDTH = 1024;
+var TEXTURE_HEIGHT = 1024;
+var TRANSPARENT_COLOR = {
+ css: 'rgba(0, 0, 0, 0)',
+ rgba: 0
};
-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);
+var FRAME_CACHE_DRAW_LIMIT = 100;
+function getGlyphCacheKey(glyph) {
+ var styleFlags = (glyph.bold ? 0 : 4) + (glyph.dim ? 0 : 2) + (glyph.italic ? 0 : 1);
+ return glyph.bg + "_" + glyph.fg + "_" + styleFlags + glyph.char;
+}
+var DynamicCharAtlas = (function (_super) {
+ __extends(DynamicCharAtlas, _super);
+ function DynamicCharAtlas(document, _config) {
+ var _this = _super.call(this) || this;
+ _this._config = _config;
+ _this._drawToCacheCount = 0;
+ _this._cacheCanvas = document.createElement('canvas');
+ _this._cacheCanvas.width = TEXTURE_WIDTH;
+ _this._cacheCanvas.height = TEXTURE_HEIGHT;
+ _this._cacheCtx = _this._cacheCanvas.getContext('2d', { alpha: true });
+ var tmpCanvas = document.createElement('canvas');
+ tmpCanvas.width = _this._config.scaledCharWidth;
+ tmpCanvas.height = _this._config.scaledCharHeight;
+ _this._tmpCtx = tmpCanvas.getContext('2d', { alpha: _this._config.allowTransparency });
+ _this._width = Math.floor(TEXTURE_WIDTH / _this._config.scaledCharWidth);
+ _this._height = Math.floor(TEXTURE_HEIGHT / _this._config.scaledCharHeight);
+ var capacity = _this._width * _this._height;
+ _this._cacheMap = new LRUMap_1.default(capacity);
+ _this._cacheMap.prealloc(capacity);
+ return _this;
}
-}
-function wasMondifierKeyOnlyEvent(ev) {
- return ev.keyCode === 16 ||
- ev.keyCode === 17 ||
- ev.keyCode === 18;
-}
-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);
+ DynamicCharAtlas.prototype.beginFrame = function () {
+ this._drawToCacheCount = 0;
+ };
+ DynamicCharAtlas.prototype.draw = function (ctx, glyph, x, y) {
+ var glyphKey = getGlyphCacheKey(glyph);
+ var cacheValue = this._cacheMap.get(glyphKey);
+ if (cacheValue != null) {
+ this._drawFromCache(ctx, cacheValue, x, y);
+ return true;
+ }
+ else if (this._canCache(glyph) && this._drawToCacheCount < FRAME_CACHE_DRAW_LIMIT) {
+ var index = void 0;
+ if (this._cacheMap.size < this._cacheMap.capacity) {
+ index = this._cacheMap.size;
+ }
+ else {
+ index = this._cacheMap.peek().index;
+ }
+ var cacheValue_1 = this._drawToCache(glyph, index);
+ this._cacheMap.set(glyphKey, cacheValue_1);
+ this._drawFromCache(ctx, cacheValue_1, x, y);
+ return true;
+ }
+ return false;
+ };
+ DynamicCharAtlas.prototype._canCache = function (glyph) {
+ return glyph.code < 256;
+ };
+ DynamicCharAtlas.prototype._toCoordinates = function (index) {
+ return [
+ (index % this._width) * this._config.scaledCharWidth,
+ Math.floor(index / this._width) * this._config.scaledCharHeight
+ ];
+ };
+ DynamicCharAtlas.prototype._drawFromCache = function (ctx, cacheValue, x, y) {
+ if (cacheValue.isEmpty) {
+ return;
+ }
+ var _a = this._toCoordinates(cacheValue.index), cacheX = _a[0], cacheY = _a[1];
+ ctx.drawImage(this._cacheCanvas, cacheX, cacheY, this._config.scaledCharWidth, this._config.scaledCharHeight, x, y, this._config.scaledCharWidth, this._config.scaledCharHeight);
+ };
+ DynamicCharAtlas.prototype._getColorFromAnsiIndex = function (idx) {
+ if (idx < this._config.colors.ansi.length) {
+ return this._config.colors.ansi[idx];
+ }
+ return ColorManager_1.DEFAULT_ANSI_COLORS[idx];
+ };
+ DynamicCharAtlas.prototype._getBackgroundColor = function (glyph) {
+ if (this._config.allowTransparency) {
+ return TRANSPARENT_COLOR;
+ }
+ else if (glyph.bg === Types_1.INVERTED_DEFAULT_COLOR) {
+ return this._config.colors.foreground;
+ }
+ else if (glyph.bg < 256) {
+ return this._getColorFromAnsiIndex(glyph.bg);
+ }
+ return this._config.colors.background;
+ };
+ DynamicCharAtlas.prototype._getForegroundColor = function (glyph) {
+ if (glyph.fg === Types_1.INVERTED_DEFAULT_COLOR) {
+ return this._config.colors.background;
+ }
+ else if (glyph.fg < 256) {
+ return this._getColorFromAnsiIndex(glyph.fg);
+ }
+ return this._config.colors.foreground;
+ };
+ DynamicCharAtlas.prototype._drawToCache = function (glyph, index) {
+ this._drawToCacheCount++;
+ this._tmpCtx.save();
+ var backgroundColor = this._getBackgroundColor(glyph);
+ this._tmpCtx.globalCompositeOperation = 'copy';
+ this._tmpCtx.fillStyle = backgroundColor.css;
+ this._tmpCtx.fillRect(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight);
+ this._tmpCtx.globalCompositeOperation = 'source-over';
+ var fontWeight = glyph.bold ? this._config.fontWeightBold : this._config.fontWeight;
+ var fontStyle = glyph.italic ? 'italic' : '';
+ this._tmpCtx.font =
+ fontStyle + " " + fontWeight + " " + this._config.fontSize * this._config.devicePixelRatio + "px " + this._config.fontFamily;
+ this._tmpCtx.textBaseline = 'top';
+ this._tmpCtx.fillStyle = this._getForegroundColor(glyph).css;
+ if (glyph.dim) {
+ this._tmpCtx.globalAlpha = Types_1.DIM_OPACITY;
+ }
+ this._tmpCtx.fillText(glyph.char, 0, 0);
+ this._tmpCtx.restore();
+ var imageData = this._tmpCtx.getImageData(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight);
+ var isEmpty = false;
+ if (!this._config.allowTransparency) {
+ isEmpty = CharAtlasGenerator_1.clearColor(imageData, backgroundColor);
+ }
+ var _a = this._toCoordinates(index), x = _a[0], y = _a[1];
+ this._cacheCtx.putImageData(imageData, x, y);
+ return {
+ index: index,
+ isEmpty: isEmpty
+ };
+ };
+ return DynamicCharAtlas;
+}(BaseCharAtlas_1.default));
+exports.default = DynamicCharAtlas;
+
+},{"../../shared/atlas/CharAtlasGenerator":42,"../ColorManager":25,"./BaseCharAtlas":32,"./LRUMap":36,"./Types":39}],36:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var LRUMap = (function () {
+ function LRUMap(capacity) {
+ this.capacity = capacity;
+ this._map = {};
+ this._head = null;
+ this._tail = null;
+ this._nodePool = [];
+ this.size = 0;
+ }
+ LRUMap.prototype._unlinkNode = function (node) {
+ var prev = node.prev;
+ var next = node.next;
+ if (node === this._head) {
+ this._head = next;
+ }
+ if (node === this._tail) {
+ this._tail = prev;
+ }
+ if (prev !== null) {
+ prev.next = next;
+ }
+ if (next !== null) {
+ next.prev = prev;
+ }
+ };
+ LRUMap.prototype._appendNode = function (node) {
+ var tail = this._tail;
+ if (tail !== null) {
+ tail.next = node;
+ }
+ node.prev = tail;
+ node.next = null;
+ this._tail = node;
+ if (this._head === null) {
+ this._head = node;
+ }
+ };
+ LRUMap.prototype.prealloc = function (count) {
+ var nodePool = this._nodePool;
+ for (var i = 0; i < count; i++) {
+ nodePool.push({
+ prev: null,
+ next: null,
+ key: null,
+ value: null
+ });
+ }
+ };
+ LRUMap.prototype.get = function (key) {
+ var node = this._map[key];
+ if (node !== undefined) {
+ this._unlinkNode(node);
+ this._appendNode(node);
+ return node.value;
+ }
+ return null;
+ };
+ LRUMap.prototype.peek = function () {
+ var head = this._head;
+ return head === null ? null : head.value;
+ };
+ LRUMap.prototype.set = function (key, value) {
+ var node = this._map[key];
+ if (node !== undefined) {
+ node = this._map[key];
+ this._unlinkNode(node);
+ node.value = value;
+ }
+ else if (this.size >= this.capacity) {
+ node = this._head;
+ this._unlinkNode(node);
+ delete this._map[node.key];
+ node.key = key;
+ node.value = value;
+ this._map[key] = node;
+ }
+ else {
+ var nodePool = this._nodePool;
+ if (nodePool.length > 0) {
+ node = nodePool.pop();
+ node.key = key;
+ node.value = value;
+ }
+ else {
+ node = {
+ prev: null,
+ next: null,
+ key: key,
+ value: value
+ };
+ }
+ this._map[key] = node;
+ this.size++;
+ }
+ this._appendNode(node);
+ };
+ return LRUMap;
+}());
+exports.default = LRUMap;
+
+},{}],37:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var BaseCharAtlas_1 = require("./BaseCharAtlas");
+var NoneCharAtlas = (function (_super) {
+ __extends(NoneCharAtlas, _super);
+ function NoneCharAtlas(document, config) {
+ return _super.call(this) || this;
+ }
+ NoneCharAtlas.prototype.draw = function (ctx, glyph, x, y) {
+ return false;
+ };
+ return NoneCharAtlas;
+}(BaseCharAtlas_1.default));
+exports.default = NoneCharAtlas;
+
+},{"./BaseCharAtlas":32}],38:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Types_1 = require("./Types");
+var Types_2 = require("../../shared/atlas/Types");
+var CharAtlasGenerator_1 = require("../../shared/atlas/CharAtlasGenerator");
+var BaseCharAtlas_1 = require("./BaseCharAtlas");
+var StaticCharAtlas = (function (_super) {
+ __extends(StaticCharAtlas, _super);
+ function StaticCharAtlas(_document, _config) {
+ var _this = _super.call(this) || this;
+ _this._document = _document;
+ _this._config = _config;
+ _this._canvasFactory = function (width, height) {
+ var canvas = _this._document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ return canvas;
+ };
+ return _this;
+ }
+ StaticCharAtlas.prototype._doWarmUp = function () {
+ var _this = this;
+ var result = CharAtlasGenerator_1.generateStaticCharAtlasTexture(window, this._canvasFactory, this._config);
+ if (result instanceof HTMLCanvasElement) {
+ this._texture = result;
+ }
+ else {
+ result.then(function (texture) {
+ _this._texture = texture;
+ });
+ }
+ };
+ StaticCharAtlas.prototype._isCached = function (glyph, colorIndex) {
+ var isAscii = glyph.code < 256;
+ var isBasicColor = glyph.fg < 16;
+ var isDefaultColor = glyph.fg >= 256;
+ var isDefaultBackground = glyph.bg >= 256;
+ return isAscii && (isBasicColor || isDefaultColor) && isDefaultBackground && !glyph.italic;
+ };
+ StaticCharAtlas.prototype.draw = function (ctx, glyph, x, y) {
+ if (this._texture == null) {
+ return false;
+ }
+ var colorIndex = 0;
+ if (glyph.fg < 256) {
+ colorIndex = 2 + glyph.fg + (glyph.bold ? 16 : 0);
+ }
+ else {
+ if (glyph.bold) {
+ colorIndex = 1;
+ }
+ }
+ if (!this._isCached(glyph, colorIndex)) {
+ return false;
+ }
+ ctx.save();
+ var charAtlasCellWidth = this._config.scaledCharWidth + Types_2.CHAR_ATLAS_CELL_SPACING;
+ var charAtlasCellHeight = this._config.scaledCharHeight + Types_2.CHAR_ATLAS_CELL_SPACING;
+ if (glyph.dim) {
+ ctx.globalAlpha = Types_1.DIM_OPACITY;
+ }
+ ctx.drawImage(this._texture, glyph.code * charAtlasCellWidth, colorIndex * charAtlasCellHeight, charAtlasCellWidth, this._config.scaledCharHeight, x, y, charAtlasCellWidth, this._config.scaledCharHeight);
+ ctx.restore();
+ return true;
+ };
+ return StaticCharAtlas;
+}(BaseCharAtlas_1.default));
+exports.default = StaticCharAtlas;
+
+},{"../../shared/atlas/CharAtlasGenerator":42,"../../shared/atlas/Types":43,"./BaseCharAtlas":32,"./Types":39}],39:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.INVERTED_DEFAULT_COLOR = -1;
+exports.DIM_OPACITY = 0.5;
+
+},{}],40:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventEmitter_1 = require("../../EventEmitter");
+var ColorManager_1 = require("../ColorManager");
+var RenderDebouncer_1 = require("../../ui/RenderDebouncer");
+var DomRendererRowFactory_1 = require("./DomRendererRowFactory");
+var TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
+var ROW_CONTAINER_CLASS = 'xterm-rows';
+var FG_CLASS_PREFIX = 'xterm-fg-';
+var BG_CLASS_PREFIX = 'xterm-bg-';
+var FOCUS_CLASS = 'xterm-focus';
+var SELECTION_CLASS = 'xterm-selection';
+var nextTerminalId = 1;
+var DomRenderer = (function (_super) {
+ __extends(DomRenderer, _super);
+ function DomRenderer(_terminal, theme) {
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._terminalClass = nextTerminalId++;
+ _this._rowElements = [];
+ var allowTransparency = _this._terminal.options.allowTransparency;
+ _this.colorManager = new ColorManager_1.ColorManager(document, allowTransparency);
+ _this.setTheme(theme);
+ _this._rowContainer = document.createElement('div');
+ _this._rowContainer.classList.add(ROW_CONTAINER_CLASS);
+ _this._rowContainer.style.lineHeight = 'normal';
+ _this._rowContainer.setAttribute('aria-hidden', 'true');
+ _this._refreshRowElements(_this._terminal.rows, _this._terminal.cols);
+ _this._selectionContainer = document.createElement('div');
+ _this._selectionContainer.classList.add(SELECTION_CLASS);
+ _this._selectionContainer.setAttribute('aria-hidden', 'true');
+ _this.dimensions = {
+ scaledCharWidth: null,
+ scaledCharHeight: null,
+ scaledCellWidth: null,
+ scaledCellHeight: null,
+ scaledCharLeft: null,
+ scaledCharTop: null,
+ scaledCanvasWidth: null,
+ scaledCanvasHeight: null,
+ canvasWidth: null,
+ canvasHeight: null,
+ actualCellWidth: null,
+ actualCellHeight: null
+ };
+ _this._updateDimensions();
+ _this._renderDebouncer = new RenderDebouncer_1.RenderDebouncer(_this._terminal, _this._renderRows.bind(_this));
+ _this._rowFactory = new DomRendererRowFactory_1.DomRendererRowFactory(document);
+ _this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + _this._terminalClass);
+ _this._terminal.screenElement.appendChild(_this._rowContainer);
+ _this._terminal.screenElement.appendChild(_this._selectionContainer);
+ return _this;
+ }
+ DomRenderer.prototype._updateDimensions = function () {
+ var _this = this;
+ this.dimensions.scaledCharWidth = this._terminal.charMeasure.width * window.devicePixelRatio;
+ this.dimensions.scaledCharHeight = this._terminal.charMeasure.height * window.devicePixelRatio;
+ this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth;
+ this.dimensions.scaledCellHeight = this.dimensions.scaledCharHeight;
+ this.dimensions.scaledCharLeft = 0;
+ this.dimensions.scaledCharTop = 0;
+ this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._terminal.cols;
+ this.dimensions.scaledCanvasHeight = this.dimensions.scaledCellHeight * this._terminal.rows;
+ this.dimensions.canvasWidth = this._terminal.charMeasure.width * this._terminal.cols;
+ this.dimensions.canvasHeight = this._terminal.charMeasure.height * this._terminal.rows;
+ this.dimensions.actualCellWidth = this._terminal.charMeasure.width;
+ this.dimensions.actualCellHeight = this._terminal.charMeasure.height;
+ this._rowElements.forEach(function (element) {
+ element.style.width = _this.dimensions.canvasWidth + "px";
+ element.style.height = _this._terminal.charMeasure.height + "px";
+ });
+ if (!this._dimensionsStyleElement) {
+ this._dimensionsStyleElement = document.createElement('style');
+ this._terminal.screenElement.appendChild(this._dimensionsStyleElement);
+ }
+ var styles = this._terminalSelector + " ." + ROW_CONTAINER_CLASS + " span {" +
+ " display: inline-block;" +
+ " height: 100%;" +
+ " vertical-align: top;" +
+ (" width: " + this._terminal.charMeasure.width + "px") +
+ "}";
+ this._dimensionsStyleElement.innerHTML = styles;
+ this._selectionContainer.style.height = this._terminal._viewportElement.style.height;
+ this._rowContainer.style.width = this.dimensions.canvasWidth + "px";
+ this._rowContainer.style.height = this.dimensions.canvasHeight + "px";
+ };
+ DomRenderer.prototype.setTheme = function (theme) {
+ var _this = this;
+ if (theme) {
+ this.colorManager.setTheme(theme);
+ }
+ if (!this._themeStyleElement) {
+ this._themeStyleElement = document.createElement('style');
+ this._terminal.screenElement.appendChild(this._themeStyleElement);
+ }
+ var styles = this._terminalSelector + " ." + ROW_CONTAINER_CLASS + " {" +
+ (" color: " + this.colorManager.colors.foreground.css + ";") +
+ (" background-color: " + this.colorManager.colors.background.css + ";") +
+ (" font-family: " + this._terminal.getOption('fontFamily') + ";") +
+ (" font-size: " + this._terminal.getOption('fontSize') + "px;") +
+ "}";
+ styles +=
+ this._terminalSelector + " span:not(." + DomRendererRowFactory_1.BOLD_CLASS + ") {" +
+ (" font-weight: " + this._terminal.options.fontWeight + ";") +
+ "}" +
+ (this._terminalSelector + " span." + DomRendererRowFactory_1.BOLD_CLASS + " {") +
+ (" font-weight: " + this._terminal.options.fontWeightBold + ";") +
+ "}" +
+ (this._terminalSelector + " span." + DomRendererRowFactory_1.ITALIC_CLASS + " {") +
+ " font-style: italic;" +
+ "}";
+ styles +=
+ this._terminalSelector + " ." + ROW_CONTAINER_CLASS + "." + FOCUS_CLASS + " ." + DomRendererRowFactory_1.CURSOR_CLASS + " {" +
+ (" background-color: " + this.colorManager.colors.cursor.css + ";") +
+ (" color: " + this.colorManager.colors.cursorAccent.css + ";") +
+ "}" +
+ (this._terminalSelector + " ." + ROW_CONTAINER_CLASS + ":not(." + FOCUS_CLASS + ") ." + DomRendererRowFactory_1.CURSOR_CLASS + " {") +
+ " outline: 1px solid #fff;" +
+ " outline-offset: -1px;" +
+ "}";
+ styles +=
+ this._terminalSelector + " ." + SELECTION_CLASS + " {" +
+ " position: absolute;" +
+ " top: 0;" +
+ " left: 0;" +
+ " z-index: 1;" +
+ " pointer-events: none;" +
+ "}" +
+ (this._terminalSelector + " ." + SELECTION_CLASS + " div {") +
+ " position: absolute;" +
+ (" background-color: " + this.colorManager.colors.selection.css + ";") +
+ "}";
+ this.colorManager.colors.ansi.forEach(function (c, i) {
+ styles +=
+ _this._terminalSelector + " ." + FG_CLASS_PREFIX + i + " { color: " + c.css + "; }" +
+ (_this._terminalSelector + " ." + BG_CLASS_PREFIX + i + " { background-color: " + c.css + "; }");
+ });
+ this._themeStyleElement.innerHTML = styles;
+ return this.colorManager.colors;
+ };
+ DomRenderer.prototype.onWindowResize = function (devicePixelRatio) {
+ this._updateDimensions();
+ };
+ DomRenderer.prototype._refreshRowElements = function (cols, rows) {
+ for (var i = this._rowElements.length; i <= rows; i++) {
+ var row = document.createElement('div');
+ this._rowContainer.appendChild(row);
+ this._rowElements.push(row);
+ }
+ while (this._rowElements.length > rows) {
+ this._rowContainer.removeChild(this._rowElements.pop());
+ }
+ };
+ DomRenderer.prototype.onResize = function (cols, rows) {
+ this._refreshRowElements(cols, rows);
+ this._updateDimensions();
+ };
+ DomRenderer.prototype.onCharSizeChanged = function () {
+ this._updateDimensions();
+ };
+ DomRenderer.prototype.onBlur = function () {
+ this._rowContainer.classList.remove(FOCUS_CLASS);
+ };
+ DomRenderer.prototype.onFocus = function () {
+ this._rowContainer.classList.add(FOCUS_CLASS);
+ };
+ DomRenderer.prototype.onSelectionChanged = function (start, end, columnSelectMode) {
+ while (this._selectionContainer.children.length) {
+ this._selectionContainer.removeChild(this._selectionContainer.children[0]);
+ }
+ if (!start || !end) {
+ return;
+ }
+ var viewportStartRow = start[1] - this._terminal.buffer.ydisp;
+ var viewportEndRow = end[1] - this._terminal.buffer.ydisp;
+ var viewportCappedStartRow = Math.max(viewportStartRow, 0);
+ var viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1);
+ if (viewportCappedStartRow >= this._terminal.rows || viewportCappedEndRow < 0) {
+ return;
+ }
+ var documentFragment = document.createDocumentFragment();
+ var startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
+ if (columnSelectMode) {
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, end[0], viewportCappedEndRow - viewportStartRow + 1));
+ }
+ else {
+ var endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
+ var middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._terminal.cols, middleRowsCount));
+ if (viewportCappedStartRow !== viewportCappedEndRow) {
+ var endCol_1 = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol_1));
+ }
+ }
+ this._selectionContainer.appendChild(documentFragment);
+ };
+ DomRenderer.prototype._createSelectionElement = function (row, colStart, colEnd, rowCount) {
+ if (rowCount === void 0) { rowCount = 1; }
+ var element = document.createElement('div');
+ element.style.height = rowCount * this._terminal.charMeasure.height + "px";
+ element.style.top = row * this._terminal.charMeasure.height + "px";
+ element.style.left = colStart * this._terminal.charMeasure.width + "px";
+ element.style.width = this._terminal.charMeasure.width * (colEnd - colStart) + "px";
+ return element;
+ };
+ DomRenderer.prototype.onCursorMove = function () {
+ };
+ DomRenderer.prototype.onOptionsChanged = function () {
+ this._updateDimensions();
+ this.setTheme(undefined);
+ this._terminal.refresh(0, this._terminal.rows - 1);
+ };
+ DomRenderer.prototype.clear = function () {
+ this._rowElements.forEach(function (e) { return e.innerHTML = ''; });
+ };
+ DomRenderer.prototype.refreshRows = function (start, end) {
+ this._renderDebouncer.refresh(start, end);
+ };
+ DomRenderer.prototype._renderRows = function (start, end) {
+ var terminal = this._terminal;
+ var cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y;
+ var cursorX = this._terminal.buffer.x;
+ for (var y = start; y <= end; y++) {
+ var rowElement = this._rowElements[y];
+ rowElement.innerHTML = '';
+ var row = y + terminal.buffer.ydisp;
+ var lineData = terminal.buffer.lines.get(row);
+ rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorX, terminal.charMeasure.width, terminal.cols));
+ }
+ this._terminal.emit('refresh', { start: start, end: end });
+ };
+ Object.defineProperty(DomRenderer.prototype, "_terminalSelector", {
+ get: function () {
+ return "." + TERMINAL_CLASS_PREFIX + this._terminalClass;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ return DomRenderer;
+}(EventEmitter_1.EventEmitter));
+exports.DomRenderer = DomRenderer;
+
+},{"../../EventEmitter":7,"../../ui/RenderDebouncer":48,"../ColorManager":25,"./DomRendererRowFactory":41}],41:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Buffer_1 = require("../../Buffer");
+exports.BOLD_CLASS = 'xterm-bold';
+exports.ITALIC_CLASS = 'xterm-italic';
+exports.CURSOR_CLASS = 'xterm-cursor';
+var DomRendererRowFactory = (function () {
+ function DomRendererRowFactory(_document) {
+ this._document = _document;
+ }
+ DomRendererRowFactory.prototype.createRow = function (lineData, isCursorRow, cursorX, cellWidth, cols) {
+ var fragment = this._document.createDocumentFragment();
+ var colCount = 0;
+ for (var x = 0; x < lineData.length; x++) {
+ if (colCount >= cols) {
+ continue;
+ }
+ var charData = lineData[x];
+ var char = charData[Buffer_1.CHAR_DATA_CHAR_INDEX];
+ var attr = charData[Buffer_1.CHAR_DATA_ATTR_INDEX];
+ var width = charData[Buffer_1.CHAR_DATA_WIDTH_INDEX];
+ if (width === 0) {
+ continue;
+ }
+ var charElement = this._document.createElement('span');
+ if (width > 1) {
+ charElement.style.width = cellWidth * width + "px";
+ }
+ var flags = attr >> 18;
+ var bg = attr & 0x1ff;
+ var fg = (attr >> 9) & 0x1ff;
+ if (isCursorRow && x === cursorX) {
+ charElement.classList.add(exports.CURSOR_CLASS);
+ }
+ if (flags & 8) {
+ var temp = bg;
+ bg = fg;
+ fg = temp;
+ if (fg === 256) {
+ fg = 0;
+ }
+ if (bg === 257) {
+ bg = 15;
+ }
+ }
+ if (flags & 1) {
+ if (fg < 8) {
+ fg += 8;
+ }
+ charElement.classList.add(exports.BOLD_CLASS);
+ }
+ if (flags & 64) {
+ charElement.classList.add(exports.ITALIC_CLASS);
+ }
+ charElement.textContent = char;
+ if (fg !== 257) {
+ charElement.classList.add("xterm-fg-" + fg);
+ }
+ if (bg !== 256) {
+ charElement.classList.add("xterm-bg-" + bg);
+ }
+ fragment.appendChild(charElement);
+ colCount += width;
+ }
+ return fragment;
+ };
+ return DomRendererRowFactory;
+}());
+exports.DomRendererRowFactory = DomRendererRowFactory;
+
+},{"../../Buffer":2}],42:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Types_1 = require("./Types");
+var Browser_1 = require("../utils/Browser");
+function generateStaticCharAtlasTexture(context, canvasFactory, config) {
+ var cellWidth = config.scaledCharWidth + Types_1.CHAR_ATLAS_CELL_SPACING;
+ var cellHeight = config.scaledCharHeight + Types_1.CHAR_ATLAS_CELL_SPACING;
+ var canvas = canvasFactory(255 * cellWidth, (2 + 16 + 16) * cellHeight);
+ var ctx = canvas.getContext('2d', { alpha: config.allowTransparency });
+ ctx.fillStyle = config.colors.background.css;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.save();
+ ctx.fillStyle = config.colors.foreground.css;
+ ctx.font = getFont(config.fontWeight, config);
+ ctx.textBaseline = 'top';
+ for (var i = 0; i < 256; i++) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(i * cellWidth, 0, cellWidth, cellHeight);
+ ctx.clip();
+ ctx.fillText(String.fromCharCode(i), i * cellWidth, 0);
+ ctx.restore();
+ }
+ ctx.save();
+ ctx.font = getFont(config.fontWeightBold, config);
+ for (var i = 0; i < 256; i++) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(i * cellWidth, cellHeight, cellWidth, cellHeight);
+ ctx.clip();
+ ctx.fillText(String.fromCharCode(i), i * cellWidth, cellHeight);
+ ctx.restore();
+ }
+ ctx.restore();
+ ctx.font = getFont(config.fontWeight, config);
+ for (var colorIndex = 0; colorIndex < 16; colorIndex++) {
+ var y = (colorIndex + 2) * cellHeight;
+ for (var i = 0; i < 256; i++) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(i * cellWidth, y, cellWidth, cellHeight);
+ ctx.clip();
+ ctx.fillStyle = config.colors.ansi[colorIndex].css;
+ ctx.fillText(String.fromCharCode(i), i * cellWidth, y);
+ ctx.restore();
}
}
- return keys;
+ ctx.font = getFont(config.fontWeightBold, config);
+ for (var colorIndex = 0; colorIndex < 16; colorIndex++) {
+ var y = (colorIndex + 2 + 16) * cellHeight;
+ for (var i = 0; i < 256; i++) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(i * cellWidth, y, cellWidth, cellHeight);
+ ctx.clip();
+ ctx.fillStyle = config.colors.ansi[colorIndex].css;
+ ctx.fillText(String.fromCharCode(i), i * cellWidth, y);
+ ctx.restore();
+ }
+ }
+ ctx.restore();
+ if (!('createImageBitmap' in context) || Browser_1.isFirefox || Browser_1.isSafari) {
+ if (canvas instanceof HTMLCanvasElement) {
+ return canvas;
+ }
+ return new Promise(function (r) { return r(canvas.transferToImageBitmap()); });
+ }
+ var charAtlasImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ clearColor(charAtlasImageData, config.colors.background);
+ return context.createImageBitmap(charAtlasImageData);
+}
+exports.generateStaticCharAtlasTexture = generateStaticCharAtlasTexture;
+function clearColor(imageData, color) {
+ var isEmpty = true;
+ var r = color.rgba >>> 24;
+ var g = color.rgba >>> 16 & 0xFF;
+ var b = color.rgba >>> 8 & 0xFF;
+ for (var offset = 0; offset < imageData.data.length; offset += 4) {
+ if (imageData.data[offset] === r &&
+ imageData.data[offset + 1] === g &&
+ imageData.data[offset + 2] === b) {
+ imageData.data[offset + 3] = 0;
+ }
+ else {
+ isEmpty = false;
+ }
+ }
+ return isEmpty;
+}
+exports.clearColor = clearColor;
+function getFont(fontWeight, config) {
+ return fontWeight + " " + config.fontSize * config.devicePixelRatio + "px " + config.fontFamily;
}
-Terminal.translateBufferLineToString = BufferLine_1.translateBufferLineToString;
-Terminal.EventEmitter = EventEmitter_1.EventEmitter;
-Terminal.inherits = inherits;
-Terminal.on = on;
-Terminal.off = off;
-Terminal.cancel = cancel;
-module.exports = Terminal;
+},{"../utils/Browser":44,"./Types":43}],43:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.CHAR_ATLAS_CELL_SPACING = 1;
+},{}],44:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var isNode = (typeof navigator === 'undefined') ? true : false;
+var userAgent = (isNode) ? 'node' : navigator.userAgent;
+var platform = (isNode) ? 'node' : navigator.platform;
+exports.isFirefox = !!~userAgent.indexOf('Firefox');
+exports.isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);
+exports.isMSIE = !!~userAgent.indexOf('MSIE') || !!~userAgent.indexOf('Trident');
+exports.isMac = contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform);
+exports.isIpad = platform === 'iPad';
+exports.isIphone = platform === 'iPhone';
+exports.isMSWindows = contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform);
+exports.isLinux = platform.indexOf('Linux') >= 0;
+function contains(arr, el) {
+ return arr.indexOf(el) >= 0;
+}
-},{"./BufferSet":2,"./CompositionHelper":4,"./EscapeSequences":5,"./EventEmitter":6,"./InputHandler":7,"./Linkifier":8,"./Parser":9,"./Renderer":10,"./SelectionManager":11,"./Viewport":13,"./handlers/Clipboard":14,"./utils/Browser":15,"./utils/BufferLine":16,"./utils/CharMeasure":17,"./utils/Mouse":21}]},{},[22])(22)
+},{}],45:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventEmitter_1 = require("../EventEmitter");
+var CharMeasure = (function (_super) {
+ __extends(CharMeasure, _super);
+ function CharMeasure(document, parentElement) {
+ var _this = _super.call(this) || this;
+ _this._document = document;
+ _this._parentElement = parentElement;
+ _this._measureElement = _this._document.createElement('span');
+ _this._measureElement.classList.add('xterm-char-measure-element');
+ _this._measureElement.textContent = 'W';
+ _this._measureElement.setAttribute('aria-hidden', 'true');
+ _this._parentElement.appendChild(_this._measureElement);
+ return _this;
+ }
+ Object.defineProperty(CharMeasure.prototype, "width", {
+ get: function () {
+ return this._width;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ Object.defineProperty(CharMeasure.prototype, "height", {
+ get: function () {
+ return this._height;
+ },
+ enumerable: true,
+ configurable: true
+ });
+ CharMeasure.prototype.measure = function (options) {
+ this._measureElement.style.fontFamily = options.fontFamily;
+ this._measureElement.style.fontSize = options.fontSize + "px";
+ var geometry = this._measureElement.getBoundingClientRect();
+ if (geometry.width === 0 || geometry.height === 0) {
+ return;
+ }
+ if (this._width !== geometry.width || this._height !== geometry.height) {
+ this._width = geometry.width;
+ this._height = Math.ceil(geometry.height);
+ this.emit('charsizechanged');
+ }
+ };
+ return CharMeasure;
+}(EventEmitter_1.EventEmitter));
+exports.CharMeasure = CharMeasure;
+
+},{"../EventEmitter":7}],46:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+function addDisposableDomListener(node, type, handler, useCapture) {
+ node.addEventListener(type, handler, useCapture);
+ return {
+ dispose: function () {
+ if (!handler) {
+ return;
+ }
+ node.removeEventListener(type, handler, useCapture);
+ node = null;
+ handler = null;
+ }
+ };
+}
+exports.addDisposableDomListener = addDisposableDomListener;
+
+},{}],47:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Lifecycle_1 = require("../common/Lifecycle");
+var Lifecycle_2 = require("./Lifecycle");
+var HOVER_DURATION = 500;
+var MouseZoneManager = (function (_super) {
+ __extends(MouseZoneManager, _super);
+ function MouseZoneManager(_terminal) {
+ var _this = _super.call(this) || this;
+ _this._terminal = _terminal;
+ _this._zones = [];
+ _this._areZonesActive = false;
+ _this._tooltipTimeout = null;
+ _this._currentZone = null;
+ _this._lastHoverCoords = [null, null];
+ _this.register(Lifecycle_2.addDisposableDomListener(_this._terminal.element, 'mousedown', function (e) { return _this._onMouseDown(e); }));
+ _this._mouseMoveListener = function (e) { return _this._onMouseMove(e); };
+ _this._clickListener = function (e) { return _this._onClick(e); };
+ return _this;
+ }
+ MouseZoneManager.prototype.dispose = function () {
+ _super.prototype.dispose.call(this);
+ this._deactivate();
+ };
+ MouseZoneManager.prototype.add = function (zone) {
+ this._zones.push(zone);
+ if (this._zones.length === 1) {
+ this._activate();
+ }
+ };
+ MouseZoneManager.prototype.clearAll = function (start, end) {
+ if (this._zones.length === 0) {
+ return;
+ }
+ if (!end) {
+ start = 0;
+ end = this._terminal.rows - 1;
+ }
+ for (var i = 0; i < this._zones.length; i++) {
+ var zone = this._zones[i];
+ if ((zone.y1 > start && zone.y1 <= end + 1) ||
+ (zone.y2 > start && zone.y2 <= end + 1) ||
+ (zone.y1 < start && zone.y2 > end + 1)) {
+ if (this._currentZone && this._currentZone === zone) {
+ this._currentZone.leaveCallback();
+ this._currentZone = null;
+ }
+ this._zones.splice(i--, 1);
+ }
+ }
+ if (this._zones.length === 0) {
+ this._deactivate();
+ }
+ };
+ MouseZoneManager.prototype._activate = function () {
+ if (!this._areZonesActive) {
+ this._areZonesActive = true;
+ this._terminal.element.addEventListener('mousemove', this._mouseMoveListener);
+ this._terminal.element.addEventListener('click', this._clickListener);
+ }
+ };
+ MouseZoneManager.prototype._deactivate = function () {
+ if (this._areZonesActive) {
+ this._areZonesActive = false;
+ this._terminal.element.removeEventListener('mousemove', this._mouseMoveListener);
+ this._terminal.element.removeEventListener('click', this._clickListener);
+ }
+ };
+ MouseZoneManager.prototype._onMouseMove = function (e) {
+ if (this._lastHoverCoords[0] !== e.pageX || this._lastHoverCoords[1] !== e.pageY) {
+ this._onHover(e);
+ this._lastHoverCoords = [e.pageX, e.pageY];
+ }
+ };
+ MouseZoneManager.prototype._onHover = function (e) {
+ var _this = this;
+ var zone = this._findZoneEventAt(e);
+ if (zone === this._currentZone) {
+ return;
+ }
+ if (this._currentZone) {
+ this._currentZone.leaveCallback();
+ this._currentZone = null;
+ if (this._tooltipTimeout) {
+ clearTimeout(this._tooltipTimeout);
+ }
+ }
+ if (!zone) {
+ return;
+ }
+ this._currentZone = zone;
+ if (zone.hoverCallback) {
+ zone.hoverCallback(e);
+ }
+ this._tooltipTimeout = setTimeout(function () { return _this._onTooltip(e); }, HOVER_DURATION);
+ };
+ MouseZoneManager.prototype._onTooltip = function (e) {
+ this._tooltipTimeout = null;
+ var zone = this._findZoneEventAt(e);
+ if (zone && zone.tooltipCallback) {
+ zone.tooltipCallback(e);
+ }
+ };
+ MouseZoneManager.prototype._onMouseDown = function (e) {
+ if (!this._areZonesActive) {
+ return;
+ }
+ var zone = this._findZoneEventAt(e);
+ if (zone) {
+ if (zone.willLinkActivate(e)) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+ }
+ };
+ MouseZoneManager.prototype._onClick = function (e) {
+ var zone = this._findZoneEventAt(e);
+ if (zone) {
+ zone.clickCallback(e);
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+ };
+ MouseZoneManager.prototype._findZoneEventAt = function (e) {
+ var coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);
+ if (!coords) {
+ return null;
+ }
+ var x = coords[0];
+ var y = coords[1];
+ for (var i = 0; i < this._zones.length; i++) {
+ var zone = this._zones[i];
+ if (zone.y1 === zone.y2) {
+ if (y === zone.y1 && x >= zone.x1 && x < zone.x2) {
+ return zone;
+ }
+ }
+ else {
+ if ((y === zone.y1 && x >= zone.x1) ||
+ (y === zone.y2 && x < zone.x2) ||
+ (y > zone.y1 && y < zone.y2)) {
+ return zone;
+ }
+ }
+ }
+ return null;
+ };
+ return MouseZoneManager;
+}(Lifecycle_1.Disposable));
+exports.MouseZoneManager = MouseZoneManager;
+var MouseZone = (function () {
+ function MouseZone(x1, y1, x2, y2, clickCallback, hoverCallback, tooltipCallback, leaveCallback, willLinkActivate) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ this.clickCallback = clickCallback;
+ this.hoverCallback = hoverCallback;
+ this.tooltipCallback = tooltipCallback;
+ this.leaveCallback = leaveCallback;
+ this.willLinkActivate = willLinkActivate;
+ }
+ return MouseZone;
+}());
+exports.MouseZone = MouseZone;
+
+},{"../common/Lifecycle":17,"./Lifecycle":46}],48:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var RenderDebouncer = (function () {
+ function RenderDebouncer(_terminal, _callback) {
+ this._terminal = _terminal;
+ this._callback = _callback;
+ this._animationFrame = null;
+ }
+ RenderDebouncer.prototype.dispose = function () {
+ if (this._animationFrame) {
+ window.cancelAnimationFrame(this._animationFrame);
+ this._animationFrame = null;
+ }
+ };
+ RenderDebouncer.prototype.refresh = function (rowStart, rowEnd) {
+ var _this = this;
+ rowStart = rowStart || 0;
+ rowEnd = rowEnd || this._terminal.rows - 1;
+ this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart;
+ this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd;
+ if (this._animationFrame) {
+ return;
+ }
+ this._animationFrame = window.requestAnimationFrame(function () { return _this._innerRefresh(); });
+ };
+ RenderDebouncer.prototype._innerRefresh = function () {
+ this._rowStart = Math.max(this._rowStart, 0);
+ this._rowEnd = Math.min(this._rowEnd, this._terminal.rows - 1);
+ this._callback(this._rowStart, this._rowEnd);
+ this._rowStart = null;
+ this._rowEnd = null;
+ this._animationFrame = null;
+ };
+ return RenderDebouncer;
+}());
+exports.RenderDebouncer = RenderDebouncer;
+
+},{}],49:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var Lifecycle_1 = require("../common/Lifecycle");
+var ScreenDprMonitor = (function (_super) {
+ __extends(ScreenDprMonitor, _super);
+ function ScreenDprMonitor() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ ScreenDprMonitor.prototype.setListener = function (listener) {
+ var _this = this;
+ if (this._listener) {
+ this.clearListener();
+ }
+ this._listener = listener;
+ this._outerListener = function () {
+ _this._listener(window.devicePixelRatio, _this._currentDevicePixelRatio);
+ _this._updateDpr();
+ };
+ this._updateDpr();
+ };
+ ScreenDprMonitor.prototype.dispose = function () {
+ _super.prototype.dispose.call(this);
+ this.clearListener();
+ };
+ ScreenDprMonitor.prototype._updateDpr = function () {
+ if (this._resolutionMediaMatchList) {
+ this._resolutionMediaMatchList.removeListener(this._outerListener);
+ }
+ this._currentDevicePixelRatio = window.devicePixelRatio;
+ this._resolutionMediaMatchList = window.matchMedia("screen and (resolution: " + window.devicePixelRatio + "dppx)");
+ this._resolutionMediaMatchList.addListener(this._outerListener);
+ };
+ ScreenDprMonitor.prototype.clearListener = function () {
+ if (!this._listener) {
+ return;
+ }
+ this._resolutionMediaMatchList.removeListener(this._outerListener);
+ this._listener = null;
+ this._outerListener = null;
+ };
+ return ScreenDprMonitor;
+}(Lifecycle_1.Disposable));
+exports.ScreenDprMonitor = ScreenDprMonitor;
+
+},{"../common/Lifecycle":17}],50:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.clone = function (val, depth) {
+ if (depth === void 0) { depth = 5; }
+ if (typeof val !== 'object') {
+ return val;
+ }
+ if (val === null) {
+ return null;
+ }
+ var clonedObject = Array.isArray(val) ? [] : {};
+ for (var key in val) {
+ clonedObject[key] = depth <= 1 ? val[key] : exports.clone(val[key], depth - 1);
+ }
+ return clonedObject;
+};
+
+},{}],51:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var MouseHelper = (function () {
+ function MouseHelper(_renderer) {
+ this._renderer = _renderer;
+ }
+ MouseHelper.getCoordsRelativeToElement = function (event, element) {
+ if (event.pageX == null) {
+ return null;
+ }
+ var originalElement = element;
+ var x = event.pageX;
+ var y = event.pageY;
+ while (element) {
+ x -= element.offsetLeft;
+ y -= element.offsetTop;
+ element = element.offsetParent;
+ }
+ element = originalElement;
+ while (element && element !== element.ownerDocument.body) {
+ x += element.scrollLeft;
+ y += element.scrollTop;
+ element = element.parentElement;
+ }
+ return [x, y];
+ };
+ MouseHelper.prototype.getCoords = function (event, element, charMeasure, lineHeight, colCount, rowCount, isSelection) {
+ if (!charMeasure.width || !charMeasure.height) {
+ return null;
+ }
+ var coords = MouseHelper.getCoordsRelativeToElement(event, element);
+ if (!coords) {
+ return null;
+ }
+ coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderer.dimensions.actualCellWidth / 2 : 0)) / this._renderer.dimensions.actualCellWidth);
+ coords[1] = Math.ceil(coords[1] / this._renderer.dimensions.actualCellHeight);
+ coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0));
+ coords[1] = Math.min(Math.max(coords[1], 1), rowCount);
+ return coords;
+ };
+ MouseHelper.prototype.getRawByteCoords = function (event, element, charMeasure, lineHeight, colCount, rowCount) {
+ var coords = this.getCoords(event, element, charMeasure, lineHeight, colCount, rowCount);
+ var x = coords[0];
+ var y = coords[1];
+ x += 32;
+ y += 32;
+ return { x: x, y: y };
+ };
+ return MouseHelper;
+}());
+exports.MouseHelper = MouseHelper;
+
+},{}],52:[function(require,module,exports){
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var Terminal_1 = require("./public/Terminal");
+module.exports = Terminal_1.Terminal;
+
+},{"./public/Terminal":23}]},{},[52])(52)
});
//# sourceMappingURL=xterm.js.map
diff --git a/apps/static/js/plugins/ztree/jquery.ztree.exhide.min.js b/apps/static/js/plugins/ztree/jquery.ztree.exhide.min.js
new file mode 100644
index 000000000..6c78a1fe9
--- /dev/null
+++ b/apps/static/js/plugins/ztree/jquery.ztree.exhide.min.js
@@ -0,0 +1,23 @@
+/*
+ * JQuery zTree exHideNodes v3.5.33
+ * http://treejs.cn/
+ *
+ * Copyright (c) 2010 Hunter.z
+ *
+ * Licensed same as jquery - MIT License
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * email: hunter.z@263.net
+ * Date: 2018-01-30
+ */
+(function(j){j.extend(!0,j.fn.zTree._z,{view:{clearOldFirstNode:function(c,a){for(var b=a.getNextNode();b;){if(b.isFirstNode){b.isFirstNode=!1;e.setNodeLineIcos(c,b);break}if(b.isLastNode)break;b=b.getNextNode()}},clearOldLastNode:function(c,a,b){for(a=a.getPreNode();a;){if(a.isLastNode){a.isLastNode=!1;b&&e.setNodeLineIcos(c,a);break}if(a.isFirstNode)break;a=a.getPreNode()}},makeDOMNodeMainBefore:function(c,a,b){a=d.isHidden(a,b);c.push("")},showNode:function(c,a){d.isHidden(c,a,!1);d.initShowForExCheck(c,a);k(a,c).show()},showNodes:function(c,a,b){if(a&&a.length!=0){var f={},g,i;for(g=0,i=a.length;g0&&!f?b[0].isFirstNode=!0:b.length>0&&e.setFirstNodeForHide(c,b)},setLastNode:function(c,a){var b=d.nodeChildren(c,a),f=d.isHidden(c,b[0]);b.length>0&&!f?b[b.length-1].isLastNode=!0:b.length>0&&e.setLastNodeForHide(c,b)},setFirstNodeForHide:function(c,a){var b,f,g;for(f=0,g=a.length;f=0;f--){b=a[f];if(b.isLastNode)break;if(!d.isHidden(c,b)&&!b.isLastNode){b.isLastNode=!0;e.setNodeLineIcos(c,b);break}else b=null}return b},setLastNodeForShow:function(c,
+a){var b,f,g,i;for(f=a.length-1;f>=0;f--){b=a[f];var h=d.isHidden(c,b);if(!g&&!h&&b.isLastNode){g=b;break}else if(!g&&!h&&!b.isLastNode)b.isLastNode=!0,g=b,e.setNodeLineIcos(c,b);else if(g&&b.isLastNode){b.isLastNode=!1;i=b;e.setNodeLineIcos(c,b);break}}return{"new":g,old:i}}},data:{initHideForExCheck:function(c,a){if(d.isHidden(c,a)&&c.check&&c.check.enable){if(typeof a._nocheck=="undefined")a._nocheck=!!a.nocheck,a.nocheck=!0;a.check_Child_State=-1;e.repairParentChkClassWithSelf&&e.repairParentChkClassWithSelf(c,
+a)}},initShowForExCheck:function(c,a){if(!d.isHidden(c,a)&&c.check&&c.check.enable){if(typeof a._nocheck!="undefined")a.nocheck=a._nocheck,delete a._nocheck;if(e.setChkClass){var b=k(a,l.id.CHECK,c);e.setChkClass(c,b,a)}e.repairParentChkClassWithSelf&&e.repairParentChkClassWithSelf(c,a)}}}});var j=j.fn.zTree,m=j._z.tools,l=j.consts,e=j._z.view,d=j._z.data,k=m.$;d.isHidden=function(c,a,b){if(!a)return!1;c=c.data.key.isHidden;typeof b!=="undefined"&&(typeof b==="string"&&(b=m.eqs(checked,"true")),a[c]=
+!!b);return a[c]};d.exSetting({data:{key:{isHidden:"isHidden"}}});d.addInitNode(function(c,a,b){a=d.isHidden(c,b);d.isHidden(c,b,a);d.initHideForExCheck(c,b)});d.addBeforeA(function(){});d.addZTreeTools(function(c,a){a.showNodes=function(a,b){e.showNodes(c,a,b)};a.showNode=function(a,b){a&&e.showNodes(c,[a],b)};a.hideNodes=function(a,b){e.hideNodes(c,a,b)};a.hideNode=function(a,b){a&&e.hideNodes(c,[a],b)};var b=a.checkNode;if(b)a.checkNode=function(f,e,i,h){(!f||!d.isHidden(c,f))&&b.apply(a,arguments)}});
+var n=d.initNode;d.initNode=function(c,a,b,f,g,i,h){var j=(f?f:d.getRoot(c))[c.data.key.children];d.tmpHideFirstNode=e.setFirstNodeForHide(c,j);d.tmpHideLastNode=e.setLastNodeForHide(c,j);h&&(e.setNodeLineIcos(c,d.tmpHideFirstNode),e.setNodeLineIcos(c,d.tmpHideLastNode));g=d.tmpHideFirstNode===b;i=d.tmpHideLastNode===b;n&&n.apply(d,arguments);h&&i&&e.clearOldLastNode(c,b,h)};var o=d.makeChkFlag;if(o)d.makeChkFlag=function(c,a){(!a||!d.isHidden(c,a))&&o.apply(d,arguments)};var p=d.getTreeCheckedNodes;
+if(p)d.getTreeCheckedNodes=function(c,a,b,f){if(a&&a.length>0){var e=a[0].getParentNode();if(e&&d.isHidden(c,e))return[]}return p.apply(d,arguments)};var q=d.getTreeChangeCheckedNodes;if(q)d.getTreeChangeCheckedNodes=function(c,a,b){if(a&&a.length>0){var e=a[0].getParentNode();if(e&&d.isHidden(c,e))return[]}return q.apply(d,arguments)};var r=e.expandCollapseSonNode;if(r)e.expandCollapseSonNode=function(c,a,b,f,g){(!a||!d.isHidden(c,a))&&r.apply(e,arguments)};var s=e.setSonNodeCheckBox;if(s)e.setSonNodeCheckBox=
+function(c,a,b,f){(!a||!d.isHidden(c,a))&&s.apply(e,arguments)};var t=e.repairParentChkClassWithSelf;if(t)e.repairParentChkClassWithSelf=function(c,a){(!a||!d.isHidden(c,a))&&t.apply(e,arguments)}})(jQuery);
diff --git a/apps/templates/_nav.html b/apps/templates/_nav.html
index 06c8e6b46..61acada82 100644
--- a/apps/templates/_nav.html
+++ b/apps/templates/_nav.html
@@ -58,7 +58,6 @@
{% endif %}
-{% if request.user.is_superuser %}
{% trans 'Job Center' %}
@@ -67,7 +66,6 @@
{% trans 'Task list' %}
-{% endif %}
{% trans 'Audits' %}
@@ -77,17 +75,9 @@
{% trans 'FTP log' %}
{% trans 'Operate log' %}
{% trans 'Password change log' %}
+ {% trans 'Command execution' %}
-{##}
-{# #}
-{# {% trans 'File' %} #}
-{# #}
-{# #}
-{# #}
{% if XPACK_PLUGINS %}
diff --git a/apps/templates/_nav_user.html b/apps/templates/_nav_user.html
index a8f2dcca1..151ed124e 100644
--- a/apps/templates/_nav_user.html
+++ b/apps/templates/_nav_user.html
@@ -4,6 +4,11 @@
{% trans 'My assets' %}
+
+
+ {% trans 'Command execution' %}
+
+
{% trans 'Profile' %}
diff --git a/apps/users/templates/users/user_granted_asset.html b/apps/users/templates/users/user_granted_asset.html
index 8a68f3f60..aac788e40 100644
--- a/apps/users/templates/users/user_granted_asset.html
+++ b/apps/users/templates/users/user_granted_asset.html
@@ -57,7 +57,6 @@
-
{% endblock %}
{% block custom_foot_js %}