🎁 Sync 2026-07-07 20:50:55

This commit is contained in:
github-actions[bot] committed 2026-07-07 20:50:55 +08:00
1 parent 5c17703277
commit 7e8d0f0093
100 files changed
+5162 -17005

No files matched your search

+15 -7
View File
@@ -7,18 +7,20 @@
include $(TOPDIR)/rules.mk
PKG_ARCH_baidudrive:=$(ARCH)
PKG_ARCH_BAIDUDRIVE:=$(ARCH)
PKG_NAME:=baidudrive
PKG_VERSION:=0.4.0
PKG_RELEASE:=2
PKG_VERSION:=1.0.1
PKG_RELEASE:=3
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/Carseason/openwrt-packages/releases/download/prebuilt/
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
PKG_HASH:=skip
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_VERSION)
PKG_BUILD_PARALLEL:=1
PKG_USE_MIPS16:=0
STRIP:=true
RSTRIP:=:
include $(INCLUDE_DIR)/package.mk
@@ -27,7 +29,7 @@ define Package/$(PKG_NAME)
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=BaiduDrive
DEPENDS:=@(x86_64||aarch64)
DEPENDS:=@(x86_64||aarch64) +curl
URL:=https://github.com/linkease/istore-packages
endef
@@ -46,8 +48,14 @@ define Build/Compile
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/uci-defaults $(1)/etc/config
$(INSTALL_BIN) $(PKG_BUILD_DIR)/baidudrive.$(PKG_ARCH_baidudrive) $(1)/usr/sbin/baidudrive
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/libexec/baidudrive $(1)/opt/baidunas-sdk $(1)/opt/baidunas-glibc $(1)/etc/init.d $(1)/etc/uci-defaults $(1)/etc/config
$(INSTALL_BIN) $(PKG_BUILD_DIR)/baidudrive.$(PKG_ARCH_BAIDUDRIVE) $(1)/usr/sbin/baidudrive
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nas_sdk/$(PKG_ARCH_BAIDUDRIVE)/baiduNas $(1)/opt/baidunas-sdk/baiduNas
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nas_sdk/$(PKG_ARCH_BAIDUDRIVE)/P2PClient.bin $(1)/opt/baidunas-sdk/P2PClient.bin
$(INSTALL_DATA) $(PKG_BUILD_DIR)/nas_sdk/$(PKG_ARCH_BAIDUDRIVE)/libkernel.so $(1)/opt/baidunas-sdk/libkernel.so
$(CP) $(PKG_BUILD_DIR)/glibc/$(PKG_ARCH_BAIDUDRIVE)/. $(1)/opt/baidunas-glibc/
$(LN) /usr/sbin/baidudrive $(1)/opt/baidunas-sdk/P2PClient
$(INSTALL_BIN) ./files/sdk-init.sh $(1)/usr/libexec/baidudrive/sdk-init.sh
$(INSTALL_BIN) ./files/baidudrive.init $(1)/etc/init.d/baidudrive
$(INSTALL_BIN) ./files/baidudrive.uci-default $(1)/etc/uci-defaults/09-baidudrive
$(INSTALL_CONF) ./files/baidudrive.config $(1)/etc/config/baidudrive
+12 -1
View File
@@ -1,4 +1,15 @@
config baidudrive
option 'enabled' '0'
option 'data_dir' ''
option 'port' '8080'
option 'host' '0.0.0.0'
option 'port' '10780'
option 'sdk_dir' '/opt/baidunas-sdk'
option 'sdk_host' '127.0.0.1'
option 'sdk_port' '8001'
option 'macid' ''
option 'device_type' ''
option 'usb_path' ''
option 'download_path' '/'
option 'quota_path' ''
option 'tmp_path' ''
option 'log_level' '7'
+108 -6
View File
@@ -6,7 +6,51 @@ USE_PROCD=1
get_config() {
config_get_bool enabled "$1" enabled 1
config_get data_dir "$1" data_dir ""
config_get port "$1" port "8080"
config_get host "$1" host "0.0.0.0"
config_get port "$1" port "10780"
config_get sdk_dir "$1" sdk_dir "/opt/baidunas-sdk"
config_get sdk_host "$1" sdk_host "127.0.0.1"
config_get sdk_port "$1" sdk_port "8001"
config_get macid "$1" macid ""
config_get device_type "$1" device_type ""
config_get usb_path "$1" usb_path ""
config_get download_path "$1" download_path "/"
config_get quota_path "$1" quota_path ""
config_get tmp_path "$1" tmp_path ""
config_get log_level "$1" log_level "7"
}
require_start_value() {
local name="$1"
local value="$2"
if [ -z "$value" ]; then
logger -t baidudrive "$name is empty; please set option $name in /etc/config/baidudrive"
return 1
fi
return 0
}
require_executable() {
local path="$1"
if [ ! -x "$path" ]; then
logger -t baidudrive "missing executable: $path"
return 1
fi
return 0
}
require_file() {
local path="$1"
if [ ! -e "$path" ]; then
logger -t baidudrive "missing runtime file: $path"
return 1
fi
return 0
}
storage_root_from_data_dir() {
local path="$1"
df -P "$path" 2>/dev/null | awk 'NR == 2 { print $6 }'
}
start_service() {
@@ -15,16 +59,74 @@ start_service() {
if [ "$enabled" != 1 ]; then
return 1
fi
if [ -z "$data_dir" ]; then
logger -t baidudrive "data_dir is empty; please set option data_dir in /etc/config/baidudrive"
return 1
fi
require_start_value data_dir "$data_dir" || return 1
require_start_value macid "$macid" || return 1
require_start_value device_type "$device_type" || return 1
require_executable /usr/sbin/baidudrive || return 1
require_executable "$sdk_dir/baiduNas" || return 1
require_executable "$sdk_dir/P2PClient" || return 1
require_executable "$sdk_dir/P2PClient.bin" || return 1
require_file "$sdk_dir/libkernel.so" || return 1
require_file /opt/baidunas-glibc || return 1
mkdir -p "$data_dir" || return 1
local storage_root
storage_root="$(storage_root_from_data_dir "$data_dir")"
if [ -n "$storage_root" ]; then
[ -n "$usb_path" ] && [ "$usb_path" != "/mnt" ] || usb_path="$storage_root"
[ -n "$quota_path" ] && [ "$quota_path" != "/mnt" ] || quota_path="$storage_root"
fi
[ -n "$usb_path" ] || usb_path="$data_dir"
[ -n "$quota_path" ] || quota_path="$usb_path"
[ -n "$tmp_path" ] || tmp_path="$data_dir/sdk-tmp"
mkdir -p "$tmp_path" || return 1
rm -rf /mnt/mnt /mnt/.baidudrive-write-test-* 2>/dev/null || true
logger -t baidudrive "Starting Baidu NAS SDK"
procd_open_instance baiduNas
procd_set_param command "$sdk_dir/baiduNas" \
-ip "$sdk_host" \
-port "$sdk_port" \
-macid "$macid" \
-type "$device_type" \
-tmppath "$tmp_path" \
-usbpath "$usb_path" \
-downloadpath "$download_path" \
-order lifo \
-forceipv4 \
-loglevel "$log_level"
procd_set_param dir "$sdk_dir"
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn
procd_close_instance
logger -t baidudrive "Starting Baidu NAS SDK init loop"
procd_open_instance sdk-init
procd_set_param command /usr/libexec/baidudrive/sdk-init.sh
procd_set_param env \
DATA_DIR="$data_dir" \
BAIDU_NAS_HOST="$sdk_host" \
BAIDU_NAS_PORT="$sdk_port" \
BAIDU_NAS_USB_PATH="$usb_path" \
BAIDU_NAS_QUOTA_PATH="$quota_path"
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn
procd_close_instance
logger -t baidudrive "Starting BaiduDrive Service"
procd_open_instance baidudrive
procd_set_param command /usr/sbin/baidudrive --port "$port" --data "$data_dir"
procd_set_param env \
BAIDU_NAS_MACID="$macid" \
BAIDU_NAS_DEVICE_TYPE="$device_type" \
BAIDU_NAS_USB_PATH="$usb_path" \
BAIDU_NAS_QUOTA_PATH="$quota_path"
procd_set_param command /usr/sbin/baidudrive --host "$host" --port "$port" --data "$data_dir"
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn
procd_close_instance
+14
View File
@@ -1,5 +1,19 @@
#!/bin/sh
[ ! -f "/usr/share/ucitrack/luci-app-baidudrive.json" ] && {
cat > /usr/share/ucitrack/luci-app-baidudrive.json << EEOF
{
"config": "baidudrive",
"init": "baidudrive"
}
EEOF
}
uci -q batch <<-EOF >/dev/null
delete ucitrack.@baidudrive[-1]
add ucitrack baidudrive
set ucitrack.@baidudrive[-1].init=baidudrive
commit ucitrack
EOF
/etc/init.d/baidudrive enable
/etc/init.d/baidudrive start
+69
View File
@@ -0,0 +1,69 @@
#!/bin/sh
set -eu
DATA_DIR=${DATA_DIR:-/mnt/baidudrive/data}
BAIDU_NAS_HOST=${BAIDU_NAS_HOST:-127.0.0.1}
BAIDU_NAS_PORT=${BAIDU_NAS_PORT:-8001}
BAIDU_NAS_USB_PATH=${BAIDU_NAS_USB_PATH:-/mnt}
BAIDU_NAS_QUOTA_PATH=${BAIDU_NAS_QUOTA_PATH:-$BAIDU_NAS_USB_PATH}
LOG_FILE="$DATA_DIR/sdk-init.log"
mkdir -p "$DATA_DIR"
log() {
printf '%s %s\n' "$(date -Iseconds 2>/dev/null || date)" "$*" >> "$LOG_FILE"
}
while true; do
token=$(sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$DATA_DIR/session.json" 2>/dev/null | head -n 1)
if [ -z "$token" ]; then
log "session token not ready"
sleep 2
continue
fi
set -- $(df -m "$BAIDU_NAS_QUOTA_PATH" | awk 'NR==2 {print $2, $4}')
total=${1:-0}
free=${2:-0}
sdk_ready=1
register_response=$(curl -fsS --max-time 10 -G \
--data-urlencode "access_token=$token" \
"http://$BAIDU_NAS_HOST:$BAIDU_NAS_PORT/register" 2>/dev/null || true)
if printf '%s' "$register_response" | grep -F '"errno":0' >/dev/null; then
device_id=$(printf '%s' "$register_response" | sed -n 's/.*"device_id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)
log "register ok device_id=${device_id:-unknown}"
else
log "register failed"
sdk_ready=0
fi
if curl -fsS --max-time 10 -G \
--data-urlencode "type=quota" \
--data-urlencode "path=$BAIDU_NAS_USB_PATH" \
--data-urlencode "free=$free" \
--data-urlencode "total=$total" \
"http://$BAIDU_NAS_HOST:$BAIDU_NAS_PORT/event" >/dev/null 2>&1; then
log "quota ok path=$BAIDU_NAS_USB_PATH total=${total} free=${free}"
else
log "quota failed"
sdk_ready=0
fi
if curl -fsS --max-time 10 -G \
--data-urlencode "type=usbIn" \
--data-urlencode "path=$BAIDU_NAS_USB_PATH" \
"http://$BAIDU_NAS_HOST:$BAIDU_NAS_PORT/event" >/dev/null 2>&1; then
log "usbIn ok path=$BAIDU_NAS_USB_PATH"
else
log "usbIn failed"
sdk_ready=0
fi
if [ "$sdk_ready" = "1" ]; then
log "sdk init ready"
sleep 60
else
sleep 2
fi
done
+2 -2
View File
@@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=baidudrive
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_VERSION:=1.0.1
PKG_RELEASE:=2
LUCI_DEPENDS:=+baidudrive +luci-compat
LUCI_MINIFY_CSS:=0
LUCI_MINIFY_JS:=0
@@ -15,9 +15,13 @@ end
function baidudrive_status()
local sys = require "luci.sys"
local uci = require "luci.model.uci".cursor()
local port = uci:get_first("baidudrive", "baidudrive", "port") or "8080"
local port = uci:get_first("baidudrive", "baidudrive", "port") or "10780"
local app_running = (sys.call("pidof baidudrive >/dev/null") == 0)
local sdk_running = (sys.call("pidof baiduNas >/dev/null") == 0)
local status = {
running = (sys.call("pidof baidudrive >/dev/null") == 0),
running = app_running and sdk_running,
app_running = app_running,
sdk_running = sdk_running,
port = port
}
luci.http.prepare_content("application/json")
@@ -24,7 +24,7 @@ end
data_dir.default = default_path
local port = s:option(Value, "port", translate("Listen port"))
port.default = "8080"
port.default = "10780"
port.rmempty = false
port.datatype = "port"
port.description = translate("Port for BaiduDrive HTTP server.")
@@ -3,7 +3,9 @@ XHR.poll(5, '<%=url("admin/services/baidudrive_status")%>', null, function(x, st
var el = document.getElementById('baidudrive_status');
if (st && el) {
if (!st.running) {
el.innerHTML = '<br/><em style=\"color:red\"><%:The BaiduDrive service is not running.%></em>';
el.innerHTML = '<br/><em style=\"color:red\"><%:The BaiduDrive service is not running.%></em>'
+ '<br/><small>baidudrive: ' + (st.app_running ? 'running' : 'stopped')
+ ', baiduNas: ' + (st.sdk_running ? 'running' : 'stopped') + '</small>';
}
if (st.running) {
el.innerHTML = '<br/><em style=\"color:green\"><%:The BaiduDrive service is running.%></em>'
@@ -0,0 +1,56 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: luasrc/controller/baidudrive.lua:10 luasrc/model/cbi/baidudrive.lua:3
msgid "BaiduDrive"
msgstr "百度网盘"
#: luasrc/model/cbi/baidudrive.lua:3
msgid "BaiduDrive provides a Baidu Netdisk Web UI."
msgstr "百度网盘提供 WEBUI"
#: luasrc/view/baidudrive/baidudrive_status.htm:10
msgid "Click to open BaiduDrive"
msgstr "点击打开百度网盘 WEBUI"
#: luasrc/view/baidudrive/baidudrive_status.htm:19
msgid "Collecting data..."
msgstr ""
#: luasrc/model/cbi/baidudrive.lua:16
msgid "Data directory"
msgstr "数据文件夹"
#: luasrc/model/cbi/baidudrive.lua:10
msgid "Enable"
msgstr "启用"
#: luasrc/model/cbi/baidudrive.lua:6
msgid "Global settings"
msgstr "全局设置"
#: luasrc/model/cbi/baidudrive.lua:26
msgid "Listen port"
msgstr "监听端口"
#: luasrc/model/cbi/baidudrive.lua:30
msgid "Port for BaiduDrive HTTP server."
msgstr "百度网盘 HTTP 服务的端口号"
#: luasrc/model/cbi/baidudrive.lua:18
msgid ""
"Required. BaiduDrive stores its config, session and task data under this "
"directory."
msgstr "必需。百度网盘在此文件夹下保存配置和会话,以及任务数据"
#: luasrc/view/baidudrive/baidudrive_status.htm:17
msgid "Status"
msgstr "状态"
#: luasrc/view/baidudrive/baidudrive_status.htm:6
msgid "The BaiduDrive service is not running."
msgstr "百度网盘未运行"
#: luasrc/view/baidudrive/baidudrive_status.htm:9
msgid "The BaiduDrive service is running."
msgstr "百度网盘运行中"
+1
View File
@@ -0,0 +1 @@
zh-cn
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede
PKG_VERSION:=1.14.7
PKG_RELEASE:=29
PKG_RELEASE:=30
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -38,4 +38,13 @@ elif command -v opkg >/dev/null 2>&1; then
latest=$(opkg info "$PKG" 2>/dev/null | awk -F': ' '$1=="Version"{print $2; exit}')
fi
case "$PKG" in
dae|daed)
case "$installed" in
20[0-9][0-9].[0-9]*) ;;
*) installed="" ;;
esac
;;
esac
printf '%s\t%s\n' "$installed" "$latest"
@@ -8,7 +8,7 @@
return view.extend({
load: function() {
return Promise.all([
fs.exec_direct('/usr/libexec/luci-mwan3', ['ipset', 'dump']),
fs.exec_direct('/usr/libexec/luci-mwan3', ['nftset', 'dump']),
uci.load('mwan3')
]);
},
@@ -66,7 +66,7 @@
"/usr/bin/arping": [
"list"
],
"/usr/libexec/luci-mwan3 ipset dump": [
"/usr/libexec/luci-mwan3 nftset dump": [
"exec"
]
},
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-openclash
PKG_VERSION:=0.47.110
PKG_RELEASE:=5
PKG_VERSION:=0.47.116
PKG_RELEASE:=6
PKG_MAINTAINER:=vernesong <https://github.com/vernesong/OpenClash>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -50,6 +50,7 @@ function index()
entry({"admin", "services", "openclash", "diag_connection"}, call("action_diag_connection"))
entry({"admin", "services", "openclash", "diag_dns"}, call("action_diag_dns"))
entry({"admin", "services", "openclash", "gen_debug_logs"}, call("action_gen_debug_logs"))
entry({"admin", "services", "openclash", "get_debug_logs"}, call("action_get_debug_logs"))
entry({"admin", "services", "openclash", "log_level"}, call("action_log_level"))
entry({"admin", "services", "openclash", "switch_log"}, call("action_switch_log"))
entry({"admin", "services", "openclash", "rule_mode"}, call("action_rule_mode"))
@@ -491,17 +492,18 @@ function set_subinfo_url()
if not filename then
info = "Oops: The config file name seems to be incorrect"
end
if url ~= "" and not string.find(url, "http") then
if url and url ~= "" and not string.find(url, "http") then
info = "Oops: The url link format seems to be incorrect"
end
if not info then
uci:foreach("openclash", "subscribe_info",
function(s)
if s.name == filename then
if url == "" then
if not url or url == "" then
uci:delete("openclash", s[".name"])
uci:commit("openclash")
info = "Delete success"
return false
else
local url_list = {}
for line in string.gmatch(url, "[^\n]+") do
@@ -513,12 +515,13 @@ function set_subinfo_url()
uci:set_list("openclash", s[".name"], "url", url_list)
uci:commit("openclash")
info = "Success"
return false
end
end
end
)
if not info then
if url == "" then
if not url or url == "" then
info = "Delete success"
else
local url_list = {}
@@ -683,6 +686,7 @@ function get_sub_url(filename)
table.insert(providers, {name = name, url = url})
end
end
return false
end
end
)
@@ -781,6 +785,7 @@ function sub_info_get()
function(s)
if s.name == filename and s.sub_ua then
sub_ua = s.sub_ua
return false
end
end
)
@@ -1418,7 +1423,12 @@ function action_refresh_log()
end
function action_del_log()
luci.sys.exec(": > /tmp/openclash.log")
local log_type = luci.http.formvalue("type")
if log_type == "debug" then
luci.sys.exec(": > /tmp/openclash_debug.log")
else
luci.sys.exec(": > /tmp/openclash.log")
end
return
end
@@ -1515,6 +1525,15 @@ function action_gen_debug_logs()
luci.http.write(info)
end
function action_get_debug_logs()
local logfile = "/tmp/openclash_debug.log"
if not fs.access(logfile) then
return
end
luci.http.prepare_content("text/plain; charset=utf-8")
luci.http.write(fs.readfile(logfile) or "")
end
function action_backup()
local config = luci.sys.call("cp /etc/config/openclash /etc/openclash/openclash >/dev/null 2>&1")
local reader = ltn12_popen("tar -C '/etc/openclash/' -cz . 2>/dev/null")
@@ -1649,49 +1668,7 @@ function rename_file()
fs.rename(old_run_file_path, new_run_file_path)
end
uci:foreach("openclash", "config_subscribe",
function(s)
if s.name == fs.filename(old_file_name) and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "name", fs.filename(new_file_name))
end
end)
uci:foreach("openclash", "subscribe_info",
function(s)
if s.name == fs.filename(old_file_name) and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "name", fs.filename(new_file_name))
end
end)
uci:foreach("openclash", "groups",
function(s)
if s.config == old_file_name and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "config", new_file_name)
end
end)
uci:foreach("openclash", "proxy-provider",
function(s)
if s.config == old_file_name and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "config", new_file_name)
end
end)
uci:foreach("openclash", "servers",
function(s)
if s.config == old_file_name and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "config", new_file_name)
end
end)
uci:foreach("openclash", "config_age_secret",
function(s)
if s.name == fs.filename(old_file_name) and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "name", fs.filename(new_file_name))
end
end)
uci:commit("openclash")
fs.config_refs(old_file_name, new_file_name)
end
luci.http.status(200, "Rename File Successful")
else
@@ -3669,6 +3646,7 @@ function action_upload_overwrite()
else
uci:set("openclash", s[".name"], "order", tonumber(order))
end
return false
end
end)
if not found then
@@ -3844,6 +3822,7 @@ function action_overwrite_subscribe_info()
uci:set("openclash", s[".name"], "enable", tostring(enable))
end
found = true
return false
end
end)
local overwrite_dir = "/etc/openclash/overwrite/"
@@ -3889,6 +3868,7 @@ function action_overwrite_subscribe_info()
uci:set("openclash", s[".name"], "enable", tostring(enable))
end
found = true
return false
end
end)
end
@@ -4017,6 +3997,7 @@ function delete_overwrite_file()
uci:foreach("openclash", "config_overwrite", function(s)
if s.name == filename then
uci:delete("openclash", s[".name"])
return false
end
end)
uci:commit("openclash")
@@ -4046,6 +4027,7 @@ function action_get_subscribe_data()
uci:foreach("openclash", "config_subscribe", function(s)
if s.name == filename then
data = s
return false
end
end)
@@ -4217,10 +4199,12 @@ function oix_login()
function(s)
if s.name == "oixCloud - smart" and s.address == sub_info[v] then
sub_match = true
return false
end
if s.name == "oixCloud - smart" and s.address ~= sub_info[v] then
sub_convert = true
sid = s['.name']
return false
end
end)
if sub_match then break end
@@ -15,17 +15,6 @@ bold_off = [[</strong>]]
align_mid = [[<p align="center">]]
align_mid_off = [[</p>]]
function IsYamlFile(e)
e=e or""
local e=string.lower(string.sub(e,-5,-1))
return e == ".yaml"
end
function IsYmlFile(e)
e=e or""
local e=string.lower(string.sub(e,-4,-1))
return e == ".yml"
end
function default_config_set(f)
local cf = fs.uci_get_config("config", "config_path")
if cf == "/etc/openclash/config/"..f or not cf or cf == "" or not fs.isfile(cf) then
@@ -95,14 +84,14 @@ HTTP.setfilehandler(
fd = nil
if fp == "config" then
CHIF = "1"
if IsYamlFile(meta.file) then
default_config_set(meta.file)
end
if IsYmlFile(meta.file) then
local ymlname=string.lower(string.sub(meta.file,0,-5))
local c=fs.rename(dir .. meta.file,"/etc/openclash/config/".. ymlname .. ".yaml")
local yamlname=ymlname .. ".yaml"
default_config_set(yamlname)
if fs.IsYamlExt(meta.file) then
if string.lower(meta.file):sub(-4) ~= ".yml" then
default_config_set(meta.file)
else
local ymlname=string.lower(string.sub(meta.file,0,-5))
local c=fs.rename(dir .. meta.file,"/etc/openclash/config/".. ymlname .. ".yaml")
default_config_set(ymlname .. ".yaml")
end
end
um.value = translate("File saved to") .. ' "/etc/openclash/config/"'
elseif fp == "proxy-provider" then
@@ -193,7 +182,7 @@ sb.template="openclash/sub_info_show"
btnis=tb:option(Button,"switch",translate("SwiTch"))
btnis.render=function(o,t,a)
if not e[t] then return false end
if IsYamlFile(e[t].name) or IsYmlFile(e[t].name) then
if fs.IsYamlExt(e[t].name) then
a.display=""
else
a.display="none"
@@ -233,7 +222,7 @@ actions.render = function(self, t, a)
table.insert(self.vallist, translate("Servers Manage"))
-- Copy
if IsYamlFile(e[t].name) or IsYmlFile(e[t].name) then
if fs.IsYamlExt(e[t].name) then
table.insert(self.keylist, "copy")
table.insert(self.vallist, translate("Copy Config"))
end
@@ -315,9 +304,13 @@ btnapply.write = function(self, t)
fd:close()
HTTP.close()
elseif action == "remove" then
local file_name = fs.basename(e[t].name)
fs.config_refs(file_name)
fs.unlink("/etc/openclash/history/"..fs.filename(e[t].name)..".db")
fs.unlink("/etc/openclash/"..fs.basename(e[t].name))
local a=fs.unlink("/etc/openclash/config/"..fs.basename(e[t].name))
fs.unlink("/etc/openclash/"..file_name)
local a=fs.unlink("/etc/openclash/config/"..file_name)
default_config_set(fs.basename(e[t].name))
if a then table.remove(e,t) end
HTTP.redirect(DISP.build_url("admin", "services", "openclash","config"))
@@ -429,5 +422,6 @@ o.write = function()
end
m:append(Template("openclash/config_editor"))
m:append(Template("openclash/config_upload"))
return ful , form , p , m
@@ -19,17 +19,6 @@ font_off = [[</b>]]
bold_on = [[<strong>]]
bold_off = [[</strong>]]
function IsYamlFile(e)
e=e or""
local e=string.lower(string.sub(e,-5,-1))
return e == ".yaml"
end
function IsYmlFile(e)
e=e or""
local e=string.lower(string.sub(e,-4,-1))
return e == ".yml"
end
m = Map(openclash, translate("Edit Group"))
m.pageaction = false
m.redirect = DISP.build_url("admin/services/openclash/servers") .. "?file=" .. HTTP.urlencode(file_path)
@@ -51,7 +40,7 @@ for t,f in ipairs(fs.glob("/etc/openclash/config/*"))do
if a then
e[t]={}
e[t].name=fs.basename(f)
if IsYamlFile(e[t].name) or IsYmlFile(e[t].name) then
if fs.IsYamlExt(e[t].name) then
o:value(e[t].name)
end
end
@@ -19,17 +19,6 @@ font_off = [[</b>]]
bold_on = [[<strong>]]
bold_off = [[</strong>]]
function IsYamlFile(e)
e=e or""
local e=string.lower(string.sub(e,-5,-1))
return e == ".yaml"
end
function IsYmlFile(e)
e=e or""
local e=string.lower(string.sub(e,-4,-1))
return e == ".yml"
end
m = Map(openclash, translate("Edit Proxy-Provider"))
m.pageaction = false
m.redirect = DISP.build_url("admin/services/openclash/servers") .. "?file=" .. HTTP.urlencode(file_path)
@@ -51,7 +40,7 @@ for t,f in ipairs(fs.glob("/etc/openclash/config/*"))do
if a then
e[t]={}
e[t].name=fs.basename(f)
if IsYamlFile(e[t].name) or IsYmlFile(e[t].name) then
if fs.IsYamlExt(e[t].name) then
o:value(e[t].name)
end
end
@@ -76,7 +65,7 @@ for t,f in ipairs(fs.glob("/etc/openclash/proxy_provider/*"))do
if h then
p[t]={}
p[t].name=fs.basename(f)
if IsYamlFile(p[t].name) or IsYmlFile(p[t].name) then
if fs.IsYamlExt(p[t].name) then
o:value("./proxy_provider/"..p[t].name)
end
end
@@ -20,16 +20,7 @@ font_off = [[</b>]]
bold_on = [[<strong>]]
bold_off = [[</strong>]]
function IsYamlFile(e)
e=e or""
local e=string.lower(string.sub(e,-5,-1))
return e == ".yaml"
end
function IsYmlFile(e)
e=e or""
local e=string.lower(string.sub(e,-4,-1))
return e == ".yml"
end
local encrypt_methods_ss = {
-- stream
@@ -132,7 +123,7 @@ for t,f in ipairs(fs.glob("/etc/openclash/config/*"))do
if a then
e[t]={}
e[t].name=fs.basename(f)
if IsYamlFile(e[t].name) or IsYmlFile(e[t].name) then
if fs.IsYamlExt(e[t].name) then
o:value(e[t].name)
end
end
@@ -78,7 +78,7 @@ s:tab("chnr_update", translate("Chnroute Update"))
s:tab("auto_restart", translate("Auto Restart"))
s:tab("version_update", translate("Version Update"))
s:tab("developer", translate("Developer Settings"))
s:tab("debug", translate("Debug Logs"))
s:tab("debug", translate("Core Tests"))
s:tab("oixcloud", translate("oixCloud"))
o = s:taboption("op_mode", ListValue, "en_mode", font_red..bold_on..translate("Select Mode")..bold_off..font_off)
+98 -1
View File
@@ -391,6 +391,7 @@ function get_age_keys(file)
if not pub and s.public then pub = s.public end
if not sec and s.secret then sec = s.secret end
end
return false
end
end)
return { public = pub, secret = sec }
@@ -457,7 +458,7 @@ end
function decode64(data)
if not data then return nil end
data = data:gsub('[%s]', '')
if #data % 4 ~= 0 then return data end
if #data % 4 ~= 0 then return nil end
local out = {}
for i = 1, #data, 4 do
@@ -487,6 +488,96 @@ function decode64(data)
return table.concat(out)
end
function config_refs(old_file_name, new_file_name)
if not old_file_name or old_file_name == "" then return end
local old_name_no_ext = filename(basename(old_file_name))
local old_file_full = basename(old_file_name)
local is_rename = new_file_name and new_file_name ~= ""
local new_name_no_ext, new_file_full
if is_rename then
new_name_no_ext = filename(basename(new_file_name))
new_file_full = basename(new_file_name)
end
uci:foreach("openclash", "config_subscribe",
function(s)
if s.name == old_name_no_ext then
if is_rename and new_name_no_ext ~= new_file_name then
uci:set("openclash", s[".name"], "name", new_name_no_ext)
else
uci:delete("openclash", s[".name"])
end
return false
end
end
)
uci:foreach("openclash", "subscribe_info",
function(s)
if s.name == old_name_no_ext then
if is_rename and new_name_no_ext ~= new_file_name then
uci:set("openclash", s[".name"], "name", new_name_no_ext)
else
uci:delete("openclash", s[".name"])
end
return false
end
end
)
uci:foreach("openclash", "groups",
function(s)
if s.config == old_file_full then
if is_rename and new_name_no_ext ~= new_file_name then
uci:set("openclash", s[".name"], "config", new_file_full)
else
uci:delete("openclash", s[".name"])
end
end
end
)
uci:foreach("openclash", "proxy-provider",
function(s)
if s.config == old_file_full then
if is_rename and new_name_no_ext ~= new_file_name then
uci:set("openclash", s[".name"], "config", new_file_full)
else
uci:delete("openclash", s[".name"])
end
end
end
)
uci:foreach("openclash", "servers",
function(s)
if s.config == old_file_full then
if is_rename and new_name_no_ext ~= new_file_name then
uci:set("openclash", s[".name"], "config", new_file_full)
else
uci:delete("openclash", s[".name"])
end
end
end
)
uci:foreach("openclash", "config_age_secret",
function(s)
if s.name == old_name_no_ext then
if is_rename and new_name_no_ext ~= new_file_name then
uci:set("openclash", s[".name"], "name", new_name_no_ext)
else
uci:delete("openclash", s[".name"])
end
return false
end
end
)
uci:commit("openclash")
end
--- Returns the appropriate ps command string for the system's ps implementation.
-- Detects procps-ng (ps -efw) vs busybox (ps -w).
-- @return String containing the ps command prefix
@@ -524,3 +615,9 @@ function oc_version()
end
return v
end
function IsYamlExt(e)
e = e or ""
local lower = string.lower(e)
return lower:sub(-5) == ".yaml" or lower:sub(-4) == ".yml"
end
@@ -1,3 +1,7 @@
<%
local fs = require "luci.openclash"
local plugin_version = fs.oc_version()
%>
<div class="oc">
<div class="config-editor-model-overlay" id="config-editor-overlay">
<div class="config-editor-model" id="config-editor-model">
@@ -93,6 +97,7 @@
</div>
</div>
<script src="/luci-static/resources/openclash/js/cm6.min.js?v=<%=plugin_version%>"></script>
<script type="text/javascript">
var levelTranslations = {
'info': '<%:Info%>',
@@ -117,6 +122,8 @@ var ConfigEditor = {
currentViewMode: 'original',
runtimeContent: '',
mergeViewActive: false,
isFullscreen: false,
mergeShowDifferences: true,
SVG_COMPARE: `
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="8" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/>
@@ -181,7 +188,16 @@ var ConfigEditor = {
} else if ((e.ctrlKey || e.metaKey) && e.key === '0') {
e.preventDefault();
self.resetZoom();
} else if (e.key === 'Escape' && (!self.editorInstance || !self.editorInstance.getOption("fullScreen"))) {
} else if (e.key === 'F11') {
e.preventDefault();
self.toggleFullscreen();
} else if (e.key === 'F10' && self.mergeViewActive) {
e.preventDefault();
self.toggleMergeDifferences();
} else if (e.key === 'Escape' && self.isFullscreen) {
e.preventDefault();
self.toggleFullscreen(false);
} else if (e.key === 'Escape' && !self.isFullscreen) {
self.closeEditor();
}
});
@@ -237,89 +253,11 @@ var ConfigEditor = {
this.makeResizable();
},
_codeMirrorLoaded: false,
_codeMirrorLoading: null,
_loadCodeMirror: function(callback) {
if (this._codeMirrorLoaded) {
if (callback) callback();
return;
}
if (this._codeMirrorLoading) {
if (callback) this._codeMirrorLoading.then(callback);
return this._codeMirrorLoading;
}
var self = this;
var basePath = '/luci-static/resources/openclash';
var head = document.head || document.getElementsByTagName('head')[0];
var cssFiles = [
'lib/codemirror.css',
'theme/material.css',
'addon/fold/foldgutter.css',
'addon/lint/lint.css',
'addon/display/fullscreen.css',
'addon/dialog/dialog.css',
'addon/search/matchesonscrollbar.css',
'addon/merge/merge.css'
];
var jsFiles = [
'lib/codemirror.js',
'mode/yaml/yaml.js',
'mode/shell/shell.js',
'mode/properties/properties.js',
'addon/fold/foldcode.js',
'addon/fold/foldgutter.js',
'addon/fold/indent-fold.js',
'addon/edit/matchbrackets.js',
'addon/selection/active-line.js',
'addon/lint/lint.js',
'addon/lint/yaml-lint.js',
'addon/lint/js-yaml.min.js',
'addon/display/fullscreen.js',
'addon/display/autorefresh.js',
'addon/dialog/dialog.js',
'addon/search/searchcursor.js',
'addon/search/search.js',
'addon/scroll/annotatescrollbar.js',
'addon/search/matchesonscrollbar.js',
'addon/search/jump-to-line.js',
'addon/merge/diff_match_patch.js',
'addon/merge/merge.js'
];
var promises = [];
cssFiles.forEach(function(file) {
promises.push(new Promise(function(resolve) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = basePath + '/' + file;
link.onload = resolve;
link.onerror = resolve;
if (head) head.appendChild(link);
else resolve();
}));
});
var loadJS = function(index) {
if (index >= jsFiles.length) return Promise.resolve();
return new Promise(function(resolve) {
var script = document.createElement('script');
script.src = basePath + '/' + jsFiles[index];
script.onload = function() { loadJS(index + 1).then(resolve); };
script.onerror = function() { loadJS(index + 1).then(resolve); };
if (head) head.appendChild(script);
else resolve();
});
};
promises.push(loadJS(0));
this._codeMirrorLoading = Promise.all(promises).then(function() {
self._codeMirrorLoaded = true;
self._codeMirrorLoading = null;
});
if (callback) this._codeMirrorLoading.then(callback);
return this._codeMirrorLoading;
},
show: function(configFile) {
var self = this;
if (typeof isDarkBackground === 'function' && isDarkBackground(document.body)) {
document.documentElement.setAttribute('data-darkmode', 'true');
}
this.isOverwrite = false;
this.currentViewMode = 'original';
this.currentConfigFile = '';
@@ -327,9 +265,10 @@ var ConfigEditor = {
this.runtimeContent = '';
this.isModified = false;
this.mergeViewActive = false;
this.isFullscreen = false;
if (this.editorInstance) {
if (this.editorInstance.toTextArea) this.editorInstance.toTextArea();
this._destroyEditor();
this.editorInstance = null;
}
var textarea = document.getElementById('config-editor-textarea');
@@ -374,9 +313,7 @@ var ConfigEditor = {
this.hideMergeView();
this.updateModeTabs();
this._loadCodeMirror(function() {
self.loadConfigContent();
});
self.loadConfigContent();
},
showOverwrite: function() {
@@ -387,9 +324,10 @@ var ConfigEditor = {
this.runtimeContent = '';
this.isModified = false;
this.mergeViewActive = false;
this.isFullscreen = false;
if (this.editorInstance) {
if (this.editorInstance.toTextArea) this.editorInstance.toTextArea();
this._destroyEditor();
this.editorInstance = null;
}
var textarea = document.getElementById('config-editor-textarea');
@@ -433,18 +371,81 @@ var ConfigEditor = {
}
this.hideMergeView();
this._loadCodeMirror(function() {
self.loadConfigContent();
});
self.loadConfigContent();
},
_destroyEditor: function() {
this.toggleFullscreen(false);
if (this.editorInstance) {
if (this.editorInstance.a && this.editorInstance.a.destroy) {
this.editorInstance.a.destroy();
if (this.editorInstance.b && this.editorInstance.b.destroy) this.editorInstance.b.destroy();
} else if (this.editorInstance.destroy) {
this.editorInstance.destroy();
} else if (this.editorInstance.toTextArea) {
this.editorInstance.toTextArea();
}
this.editorInstance = null;
}
var textarea = document.getElementById('config-editor-textarea');
if (textarea) textarea.style.display = '';
},
toggleFullscreen: function(forceState) {
var target = null;
if (this.mergeViewActive && this.editorInstance && this.editorInstance.dom) {
target = this.editorInstance.dom;
} else if (this.editorInstance && this.editorInstance.dom) {
target = this.editorInstance.dom;
}
if (!target) return;
var nextState = typeof forceState === 'boolean' ? forceState : !this.isFullscreen;
this.isFullscreen = nextState;
if (nextState) {
target.classList.add('cm-fullscreen');
target._fsOriginalParent = target.parentNode;
if (target.parentNode !== document.body) document.body.appendChild(target);
target.style.setProperty('position', 'fixed', 'important');
target.style.setProperty('top', '0', 'important');
target.style.setProperty('left', '0', 'important');
target.style.setProperty('right', '0', 'important');
target.style.setProperty('bottom', '0', 'important');
target.style.setProperty('width', '100vw', 'important');
target.style.setProperty('height', '100vh', 'important');
target.style.setProperty('z-index', '999999', 'important');
target.style.setProperty('background', 'var(--bg-light, #f5f5f5)', 'important');
} else {
target.classList.remove('cm-fullscreen');
if (target._fsOriginalParent && target._fsOriginalParent !== document.body) {
target._fsOriginalParent.appendChild(target);
}
target._fsOriginalParent = null;
target.style.position = '';
target.style.top = '';
target.style.left = '';
target.style.right = '';
target.style.bottom = '';
target.style.width = '';
target.style.height = '';
target.style.zIndex = '';
target.style.background = '';
}
},
toggleMergeDifferences: function() {
if (!this.mergeViewActive || !this.editorInstance || !this.editorInstance.reconfigure) return;
this.mergeShowDifferences = !this.mergeShowDifferences;
this.editorInstance.reconfigure({ highlightChanges: this.mergeShowDifferences, gutter: this.mergeShowDifferences });
if (this.editorInstance.dom) {
this.editorInstance.dom.classList.toggle('oc-diff-hidden', !this.mergeShowDifferences);
}
},
hide: function() {
this.overlay.classList.remove('show');
if (this.editorInstance) {
if (this.editorInstance.toTextArea) this.editorInstance.toTextArea();
this.editorInstance = null;
}
this._destroyEditor();
this.isModified = false;
this.originalContent = '';
@@ -555,53 +556,70 @@ var ConfigEditor = {
textarea.style.display = 'block';
if (self.editorInstance) {
if (self.editorInstance.toTextArea) self.editorInstance.toTextArea();
self.editorInstance = null;
self._destroyEditor();
}
self.editorInstance = CodeMirror.fromTextArea(textarea, {
mode: mode,
autoRefresh: true,
styleActiveLine: true,
lineNumbers: true,
theme: "material",
lineWrapping: true,
matchBrackets: true,
foldGutter: true,
lint: lint,
readOnly: readOnly,
gutters: lint
? ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"]
: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
extraKeys: {
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function(cm) {
if (cm.getOption("fullScreen")) {
cm.setOption("fullScreen", false);
}
},
"Tab": function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add');
} else {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
cm.replaceSelection(spaces);
}
},
"Ctrl-S": function(cm) {
if (!readOnly) self.saveConfigContent();
}
var exts = [];
var isDark = (typeof isDarkBackground === 'function' && isDarkBackground(document.body));
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
exts.push(CM6.themeExtension(isDark));
if (topSearch) exts.push(topSearch);
if (mode === 'text/yaml' || mode === 'text/x-yaml') {
exts.push(CM6.yaml());
if (lint) {
exts.push(CM6.yamlLinter());
exts.push(CM6.lintGutter());
}
exts.push(CM6.autocompletion({ override: [CM6.mihomoCompletion] }));
exts.push(CM6.indentUnit.of(" "));
exts.push(CM6.indentMarkerExtension());
} else if (mode === 'text/x-sh' || mode === 'shell') {
exts.push(CM6.StreamLanguage.define(CM6.shell));
} else if (mode === 'text/x-properties' || mode === 'properties') {
exts.push(CM6.StreamLanguage.define(CM6.properties));
}
if (readOnly) {
exts.push(CM6.EditorState.readOnly.of(true));
} else {
if (mode === 'text/yaml' || mode === 'text/x-yaml') {
exts.push(CM6.placeholderExtension('<%:Enter YAML configuration...%>'));
} else if (mode === 'text/x-sh' || mode === 'shell') {
exts.push(CM6.placeholderExtension('<%:Enter shell script...%>'));
} else {
exts.push(CM6.placeholderExtension('<%:Enter configuration...%>'));
}
}
exts.push(CM6.keymap.of([
{ key: 'Ctrl-s', run: function() {
if (!readOnly) self.saveConfigContent();
return true;
}}
]));
var parent = textarea.parentNode;
self.editorInstance = new CM6.EditorView({
state: CM6.EditorState.create({
doc: content,
extensions: [CM6.baseExtensions(), ...exts]
}),
parent: parent
});
self.editorInstance.setSize('100%', '100%');
self.editorInstance.setValue(content);
self.editorInstance.refresh();
textarea.style.display = 'none';
self.editorInstance.dom.style.height = '100%';
if (!readOnly) {
self.editorInstance.on("change", function() {
self.isModified = self.editorInstance.getValue() !== self.originalContent;
self.updateSaveButtonState();
});
var originalDispatch = self.editorInstance.dispatch;
self.editorInstance.dispatch = function(tr) {
originalDispatch.call(self.editorInstance, tr);
if (tr.docChanged) {
self.isModified = self.editorInstance.state.doc.toString() !== self.originalContent;
self.updateSaveButtonState();
}
};
}
}
@@ -685,67 +703,54 @@ var ConfigEditor = {
});
};
let showDifferences = true;
this.mergeShowDifferences = true;
Promise.all([getOriginal(), getRuntime()]).then(function(contents){
var original = contents[0] || '';
var runtime = contents[1] || '';
container.innerHTML = '';
if (self.editorInstance && self.editorInstance.toTextArea) self.editorInstance.toTextArea();
self.editorInstance = CodeMirror.MergeView(container, {
value: original,
orig: runtime,
mode: "text/yaml",
theme: "material",
lineNumbers: true,
autoRefresh: true,
styleActiveLine: true,
lineWrapping: true,
matchBrackets: true,
foldGutter: true,
lint: true,
highlightDifferences: showDifferences,
connect: null,
collapseIdentical: false,
readOnly: false,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
extraKeys: {
"F10": function() {
showDifferences = !showDifferences;
if (self.editorInstance && self.editorInstance.setShowDifferences) {
self.editorInstance.setShowDifferences(showDifferences);
}
},
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function(cm) {
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
},
"Tab": function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add');
} else {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
cm.replaceSelection(spaces);
}
},
"Ctrl-S": function(cm) {
self.saveConfigContent();
}
}
});
var leftEditor = self.editorInstance.edit;
if (leftEditor) {
leftEditor.on("change", function() {
self.isModified = leftEditor.getValue() !== self.originalContent;
self.updateSaveButtonState();
});
if (self.editorInstance) self._destroyEditor();
var isDark = (typeof isDarkBackground === 'function' && isDarkBackground(document.body));
var themeExt = CM6.themeExtension(isDark);
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
var extA = [CM6.baseExtensions(), themeExt, CM6.placeholderExtension('<%:Edit original config...%>'), CM6.yaml(), CM6.yamlLinter(), CM6.lintGutter(), CM6.autocompletion({ override: [CM6.mihomoCompletion] }), CM6.indentUnit.of(" "), CM6.indentMarkerExtension()];
var extB = [CM6.baseExtensions(), themeExt, CM6.placeholderExtension('<%:Runtime config (read only)%>'), CM6.yaml(), CM6.indentUnit.of(" "), CM6.indentMarkerExtension(), CM6.EditorState.readOnly.of(true)];
var mergeDefaults = CM6.mergeDefaultConfig || {};
if (topSearch) {
extA.push(topSearch);
extB.push(topSearch);
}
if (self.editorInstance.editor)
self.editorInstance.editor().setSize('100%', '100%');
if (self.editorInstance.rightOriginal && self.editorInstance.rightOriginal())
self.editorInstance.rightOriginal().setSize('100%', '100%');
self.editorInstance = new CM6.MergeView({
a: {
doc: original,
extensions: extA
},
b: {
doc: runtime,
extensions: extB
},
parent: container,
diffConfig: mergeDefaults.diffConfig || { scanLimit: 5000 },
gutter: typeof mergeDefaults.gutter === 'boolean' ? mergeDefaults.gutter : true,
revertControls: mergeDefaults.revertControls || 'b-to-a',
highlightChanges: self.mergeShowDifferences,
collapseUnchanged: typeof mergeDefaults.collapseUnchanged !== 'undefined' ? mergeDefaults.collapseUnchanged : false
});
var leftView = self.editorInstance.a;
if (leftView) {
var origDispatchA = leftView.dispatch;
leftView.dispatch = function(tr) {
origDispatchA.call(leftView, tr);
if (tr.docChanged) {
self.isModified = leftView.state.doc.toString() !== self.originalContent;
self.updateSaveButtonState();
}
};
}
self.mergeViewActive = true;
if (statusText) statusText.textContent = '<%:Compare mode: left(Original Config), right(Runtime Config)%>';
var layoutBtn = document.getElementById('config-editor-layout');
@@ -790,10 +795,12 @@ var ConfigEditor = {
saveBtn.disabled = true;
var content;
if (this.mergeViewActive && this.editorInstance && this.editorInstance.edit) {
content = this.editorInstance.edit.getValue();
if (this.mergeViewActive && this.editorInstance && this.editorInstance.a) {
content = this.editorInstance.a.state.doc.toString();
} else if (this.editorInstance.state) {
content = this.editorInstance.state.doc.toString();
} else {
content = this.editorInstance.getValue();
content = '';
}
if (!content) {
@@ -858,10 +865,12 @@ var ConfigEditor = {
}
var content;
if (this.mergeViewActive && this.editorInstance && this.editorInstance.edit) {
content = this.editorInstance.edit.getValue();
if (this.mergeViewActive && this.editorInstance && this.editorInstance.a) {
content = this.editorInstance.a.state.doc.toString();
} else if (this.editorInstance.state) {
content = this.editorInstance.state.doc.toString();
} else {
content = this.editorInstance.getValue();
content = '';
}
var filename;
@@ -2541,17 +2550,17 @@ var ConfigEditor = {
this.currentZoom = newZoom;
if (this.editorInstance) {
var cmWrapper = this.model.querySelector('.CodeMirror');
if (cmWrapper) {
var cmEl = null;
if (this.editorInstance.dom) cmEl = this.editorInstance.dom;
else if (this.editorInstance.a && this.editorInstance.a.dom) cmEl = this.editorInstance.a.dom;
if (cmEl) {
this.zoomLevels.forEach(function(level) {
cmWrapper.classList.remove('zoom-' + level);
cmEl.classList.remove('zoom-' + level);
});
if (this.currentZoom !== 100) {
cmWrapper.classList.add('zoom-' + this.currentZoom);
cmEl.classList.add('zoom-' + this.currentZoom);
}
this.editorInstance.refresh();
}
}
},
@@ -2773,18 +2782,6 @@ var ConfigEditor = {
self.model.style.width = newWidth + 'px';
self.model.style.height = newHeight + 'px';
if (self.editorInstance) {
requestAnimationFrame(function() {
if (self.mergeViewActive && self.editorInstance.editor) {
self.editorInstance.editor().refresh();
if (self.editorInstance.rightOriginal)
self.editorInstance.rightOriginal().refresh();
} else {
self.editorInstance.refresh();
}
});
}
}
function onMouseUp() {
@@ -2794,18 +2791,6 @@ var ConfigEditor = {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
if (self.editorInstance) {
setTimeout(function() {
if (self.mergeViewActive && self.editorInstance.editor) {
self.editorInstance.editor().refresh();
if (self.editorInstance.rightOriginal)
self.editorInstance.rightOriginal().refresh();
} else {
self.editorInstance.refresh();
}
}, 50);
}
}
resizeHandle.addEventListener('touchstart', function(e) {
@@ -2846,18 +2831,6 @@ var ConfigEditor = {
self.model.style.width = newWidth + 'px';
self.model.style.height = newHeight + 'px';
if (self.editorInstance) {
requestAnimationFrame(function() {
if (self.mergeViewActive && self.editorInstance.editor) {
self.editorInstance.editor().refresh();
if (self.editorInstance.rightOriginal)
self.editorInstance.rightOriginal().refresh();
} else {
self.editorInstance.refresh();
}
});
}
e.preventDefault();
}
@@ -2867,23 +2840,12 @@ var ConfigEditor = {
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
if (self.editorInstance) {
setTimeout(function() {
if (self.mergeViewActive && self.editorInstance.editor) {
self.editorInstance.editor().refresh();
if (self.editorInstance.rightOriginal)
self.editorInstance.rightOriginal().refresh();
} else {
self.editorInstance.refresh();
}
}, 50);
}
}
}
};
document.addEventListener('DOMContentLoaded', function() {
ConfigEditor.init();
if (typeof CM6 !== 'undefined' && CM6.startThemeObserver) CM6.startThemeObserver();
});
</script>
@@ -3,84 +3,8 @@
local plugin_version = fs.oc_version()
%>
<link rel="stylesheet" href="/luci-static/resources/openclash/css/oc.css?v=<%=plugin_version%>">
<script type="text/javascript">//<![CDATA[
var _cmReady = false;
var _cmQueue = [];
function _cmWhenReady(callback) {
if (_cmReady) { callback(); return; }
_cmQueue.push(callback);
}
(function() {
var basePath = '/luci-static/resources/openclash';
var head = document.head || document.getElementsByTagName('head')[0];
var cssFiles = [
'lib/codemirror.css',
'theme/material.css',
'theme/log.css',
'addon/fold/foldgutter.css',
'addon/lint/lint.css',
'addon/display/fullscreen.css',
'addon/dialog/dialog.css',
'addon/search/matchesonscrollbar.css',
'addon/merge/merge.css'
];
var jsFiles = [
'lib/codemirror.js',
'mode/yaml/yaml.js',
'mode/log/log.js',
'mode/shell/shell.js',
'addon/fold/foldcode.js',
'addon/fold/foldgutter.js',
'addon/fold/indent-fold.js',
'addon/edit/matchbrackets.js',
'addon/selection/active-line.js',
'addon/lint/lint.js',
'addon/lint/yaml-lint.js',
'addon/lint/js-yaml.min.js',
'addon/display/fullscreen.js',
'addon/display/autorefresh.js',
'addon/dialog/dialog.js',
'addon/search/searchcursor.js',
'addon/search/search.js',
'addon/scroll/annotatescrollbar.js',
'addon/search/matchesonscrollbar.js',
'addon/search/jump-to-line.js',
'addon/merge/diff_match_patch.js',
'addon/merge/merge.js'
];
var promises = [];
cssFiles.forEach(function(file) {
promises.push(new Promise(function(resolve) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = basePath + '/' + file;
link.onload = resolve;
link.onerror = resolve;
if (head) head.appendChild(link);
else resolve();
}));
});
var loadJS = function(index) {
if (index >= jsFiles.length) return Promise.resolve();
return new Promise(function(resolve) {
var script = document.createElement('script');
script.src = basePath + '/' + jsFiles[index];
script.onload = function() { loadJS(index + 1).then(resolve); };
script.onerror = function() { loadJS(index + 1).then(resolve); };
if (head) head.appendChild(script);
else resolve();
});
};
promises.push(loadJS(0));
Promise.all(promises).then(function() {
_cmReady = true;
var queue = _cmQueue;
_cmQueue = [];
queue.forEach(function(fn) { fn(); });
});
})();
//]]>
</script>
<script src="/luci-static/resources/openclash/js/cm6.min.js?v=<%=plugin_version%>"></script>
<script src="/luci-static/resources/openclash/js/common.js?v=<%=plugin_version%>"></script>
<%-
local uci = require("luci.model.uci").cursor()
@@ -112,7 +36,6 @@ local sid = path_info:match("(cfg[0-9a-f]+)") or ""
</tr>
</table>
<script src="/luci-static/resources/openclash/js/common.js"></script>
<script type="text/javascript">//<![CDATA[
var levelTranslations = {
'info': '<%:Info%>',
@@ -124,254 +47,278 @@ var levelTranslations = {
'fatal': '<%:Fatal%>'
};
function merge_editor(id, id2, target, target2, readOnly, readOnly2, wid, height)
{
var value, orig1, orig2, merge_editor, descr, gap, vscrollbar, vscrollbar_oc, panes = 2, highlight = true, connect = null, collapse = false;
descr = document.getElementById("my_editor_div");
target.parentNode.parentNode.parentNode.insertBefore(descr, target.parentNode.parentNode);
descr.style.display="inline-table"
value = id.value;
if (value == null) {
var _mergeShowDifferences = true;
var _fullscreenActive = false;
if (!window._ocEditorHotkeysBound) {
document.addEventListener('keydown', function(e) {
if (e.key === 'F11') {
e.preventDefault();
if (_fullscreenActive) {
CM6.toggleFullscreen(document.getElementById('oc-fullscreen-active'));
_fullscreenActive = false;
} else {
var target = CM6.getActiveEditor();
_fullscreenActive = CM6.toggleFullscreen(target);
}
return;
}
if (e.key === 'F10' && window._mergeViewInstance && window._mergeViewInstance.reconfigure) {
e.preventDefault();
_mergeShowDifferences = !_mergeShowDifferences;
window._mergeViewInstance.reconfigure({ highlightChanges: _mergeShowDifferences, gutter: _mergeShowDifferences });
if (window._mergeViewInstance.dom) {
window._mergeViewInstance.dom.classList.toggle('oc-diff-hidden', !_mergeShowDifferences);
}
return;
}
if (e.key === 'Escape' && _fullscreenActive) {
e.preventDefault();
CM6.toggleFullscreen(document.getElementById('oc-fullscreen-active'));
_fullscreenActive = false;
}
}, true);
window._ocEditorHotkeysBound = true;
}
function editor(id, readOnly, wid, height) {
var isDark = isDarkBackground(document.body);
var exts = [CM6.baseExtensions(), CM6.themeExtension(isDark), CM6.placeholderExtension('<%:Enter YAML configuration...%>')];
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
if (topSearch) exts.push(topSearch);
exts.push(CM6.yaml());
exts.push(CM6.yamlLinter());
exts.push(CM6.lintGutter());
exts.push(CM6.autocompletion({ override: [CM6.mihomoCompletion] }));
exts.push(CM6.indentUnit.of(" "));
exts.push(CM6.indentMarkerExtension());
if (readOnly) exts.push(CM6.EditorState.readOnly.of(true));
var view = new CM6.EditorView({
state: CM6.EditorState.create({ doc: id.value, extensions: exts })
});
id.parentNode.insertBefore(view.dom, id.nextSibling);
id.style.display = 'none';
id.parentNode.classList.add('oc');
if (wid && height) {
view.dom.style.width = wid;
view.dom.style.height = height;
}
var origDispatch = view.dispatch;
view.dispatch = function(tr) {
origDispatch.call(view, tr);
if (tr.docChanged) id.value = view.state.doc.toString();
};
return view;
}
function shell_editor(id, readOnly, wid, height) {
var isDark = isDarkBackground(document.body);
var exts = [CM6.baseExtensions(), CM6.themeExtension(isDark), CM6.placeholderExtension('<%:Enter shell script...%>')];
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
if (topSearch) exts.push(topSearch);
exts.push(CM6.StreamLanguage.define(CM6.shell));
if (readOnly) exts.push(CM6.EditorState.readOnly.of(true));
var view = new CM6.EditorView({
state: CM6.EditorState.create({ doc: id.value, extensions: exts })
});
id.parentNode.insertBefore(view.dom, id.nextSibling);
id.style.display = 'none';
id.parentNode.classList.add('oc');
if (wid && height) {
view.dom.style.width = wid;
view.dom.style.height = height;
}
var origDispatch = view.dispatch;
view.dispatch = function(tr) {
origDispatch.call(view, tr);
if (tr.docChanged) id.value = view.state.doc.toString();
};
return view;
}
function other_editor(id, readOnly, wid, height) {
var isDark = isDarkBackground(document.body);
var exts = [CM6.baseExtensions(), CM6.themeExtension(isDark), CM6.placeholderExtension('<%:Enter configuration...%>')];
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
if (topSearch) exts.push(topSearch);
exts.push(CM6.StreamLanguage.define(CM6.properties));
if (readOnly) exts.push(CM6.EditorState.readOnly.of(true));
var view = new CM6.EditorView({
state: CM6.EditorState.create({ doc: id.value, extensions: exts })
});
id.parentNode.insertBefore(view.dom, id.nextSibling);
id.style.display = 'none';
id.parentNode.classList.add('oc');
if (wid && height) {
view.dom.style.width = wid;
view.dom.style.height = height;
}
var origDispatch = view.dispatch;
view.dispatch = function(tr) {
origDispatch.call(view, tr);
if (tr.docChanged) id.value = view.state.doc.toString();
};
return view;
}
function log_editor(id, name, readOnly, wid, height) {
var exts = [CM6.lineNumbers(), CM6.EditorView.lineWrapping, CM6.EditorState.readOnly.of(true)];
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
if (topSearch) exts.push(topSearch);
exts.push(CM6.highlightActiveLine());
exts.push(CM6.drawSelection());
exts.push(CM6.highlightSelectionMatches());
exts.push(CM6.keymap.of(CM6.searchKeymap));
exts.push(CM6.logLanguage);
exts.push(CM6.syntaxHighlighting(CM6.logHighlightStyle));
var view = new CM6.EditorView({
state: CM6.EditorState.create({ doc: id.value, extensions: exts })
});
id.parentNode.insertBefore(view.dom, id.nextSibling);
id.style.display = 'none';
id.parentNode.classList.add('oc');
if (isDarkBackground(document.body)) {
id.parentNode.setAttribute('data-darkmode', 'true');
view.dom.setAttribute('data-darkmode', 'true');
}
window['editor_' + name] = view;
if (wid && height) {
view.dom.style.width = wid;
view.dom.style.height = height;
}
view.getValue = function() { return view.state.doc.toString(); };
view.setValue = function(v) { view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: v || '' } }); };
view.refresh = function() { view.dispatch({}); if (view.requestMeasure) view.requestMeasure(); };
view.getScrollInfo = function() { var sd = view.scrollDOM; return { top: sd.scrollTop, left: sd.scrollLeft, height: sd.scrollHeight, width: sd.scrollWidth, clientHeight: sd.clientHeight, clientWidth: sd.clientWidth }; };
view.scrollTo = function(l, t) { if (typeof l === 'object') { t = l.top; l = l.left; } view.scrollDOM.scrollTop = t || 0; view.scrollDOM.scrollLeft = l || 0; };
view.getCursor = function() { var h = view.state.selection.main.head, ln = view.state.doc.lineAt(h); return { line: ln.number - 1, ch: h - ln.from }; };
view.setCursor = function(p) { var ln = view.state.doc.line(p.line + 1); view.dispatch({ selection: { anchor: ln.from + p.ch } }); };
var _hasFocusDesc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(view), 'hasFocus');
var _hf;
if (_hasFocusDesc && _hasFocusDesc.get) {
try { _hf = function() { return _hasFocusDesc.get.call(view); }; } catch(e) { _hf = null; }
}
if (!_hf) {
_hf = function() { try { return view.contentDOM.ownerDocument.activeElement === view.contentDOM; } catch(e) { return false; } };
}
Object.defineProperty(view, 'hasFocus', { value: _hf, writable: true, configurable: true });
view.somethingSelected = function() { return !view.state.selection.main.empty; };
view.setSelection = function(f, t) { var lf = view.state.doc.line(f.line + 1), lt = view.state.doc.line(t.line + 1); view.dispatch({ selection: { anchor: lf.from + f.ch, head: lt.from + t.ch } }); };
view.scrollIntoView = function(p, m) { if (p && p.line !== undefined) { var ln = view.state.doc.line(p.line + 1); view.dispatch({ selection: { anchor: ln.from + (p.ch || 0) }, scrollIntoView: true }); } else { view.dispatch({ selection: { anchor: view.state.selection.main.head }, scrollIntoView: true }); } };
if (typeof isDarkBackground === 'function' && isDarkBackground(document.body)) {
document.documentElement.setAttribute('data-darkmode', 'true');
}
return view;
}
function markdown_editor(id, name, readOnly, wid, height) {
var isDark = (typeof isDarkBackground === 'function' && isDarkBackground(document.body));
var exts = [CM6.lineNumbers(), CM6.EditorView.lineWrapping, CM6.themeExtension(isDark), CM6.markdown()];
if (readOnly) exts.push(CM6.EditorState.readOnly.of(true));
var view = new CM6.EditorView({
state: CM6.EditorState.create({ doc: id.value || '', extensions: exts })
});
id.parentNode.insertBefore(view.dom, id.nextSibling);
id.style.display = 'none';
id.parentNode.classList.add('oc');
window['editor_' + name] = view;
if (wid && height) {
view.dom.style.width = wid;
view.dom.style.height = height;
}
view.getValue = function() { return view.state.doc.toString(); };
view.setValue = function(v) { view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: v || '' } }); };
view.refresh = function() { view.dispatch({}); };
view.dom = view.dom;
return view;
}
function merge_editor(id, id2, target, target2, readOnly, readOnly2, wid, height) {
var descr = document.getElementById("my_editor_div");
target.parentNode.parentNode.parentNode.insertBefore(descr, target.parentNode.parentNode);
descr.style.display = "inline-table";
if (!id.value) {
editor(id, readOnly, wid, height);
editor(id2, readOnly2, wid, height);
return;
}
else {
target2.parentNode.style.display="none";
orig1 = '';
orig2 = id2.value;
target.style.height= "700px"
id.style.display = "none";
id2.style.display = "none";
merge_editor = CodeMirror.MergeView(target, {
mode: "text/yaml",
value: value,
origLeft: panes == 3 ? orig1 : null,
orig: orig2,
theme: "material",
lineNumbers: true,
autoRefresh: true,
styleActiveLine: true,
lineWrapping: true,
matchBrackets: true,
foldGutter: true,
lint: true,
highlightDifferences: highlight,
connect: connect,
collapseIdentical: collapse,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
extraKeys: {
"F10": function() {
merge_editor.setShowDifferences(highlight = !highlight);
},
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
gap = document.getElementsByClassName("CodeMirror-merge-gap")[0];
vscrollbar = document.getElementsByClassName("CodeMirror-vscrollbar")[0];
vscrollbar_oc = document.getElementsByClassName("CodeMirror-vscrollbar-oc")[0];
if (cm.getOption("fullScreen")) {
console.log(gap.style.display)
gap.style.display = "none";
vscrollbar.className = "CodeMirror-vscrollbar-oc";
}
else {
gap.style.display = "";
vscrollbar_oc.className = "CodeMirror-vscrollbar";
};
},
"Esc": function(cm) {
gap = document.getElementsByClassName("CodeMirror-merge-gap")[0];
vscrollbar = document.getElementsByClassName("CodeMirror-vscrollbar")[0];
vscrollbar_oc = document.getElementsByClassName("CodeMirror-vscrollbar-oc")[0];
if (cm.getOption("fullScreen")) {
cm.setOption("fullScreen", false);
gap.style.display = "";
vscrollbar_oc.className = "CodeMirror-vscrollbar";
};
},
"Tab": function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add')
} else {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ")
cm.replaceSelection(spaces)
}
}
}
});
merge_editor.edit.on("change", function(cm) {
id.value = cm.getValue();
});
target2.parentNode.style.display = "none";
target.style.height = "700px";
target.classList.add('oc');
id.style.display = "none";
id2.style.display = "none";
if (wid && height) {
merge_editor.editor().setSize(wid, height);
merge_editor.rightOriginal().setSize(wid, height);
};
};
};
function editor(id, readOnly, wid, height)
{
var editor = CodeMirror.fromTextArea(id, {
mode: "text/yaml",
autoRefresh: true,
styleActiveLine: true,
lineNumbers: true,
theme: "material",
lineWrapping: true,
matchBrackets: true,
foldGutter: true,
lint: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
extraKeys: {
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function(cm) {
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
},
"Tab": function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add')
} else {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ")
cm.replaceSelection(spaces)
}
}
var isDark = isDarkBackground(document.body);
if (isDark) target.setAttribute('data-darkmode', 'true');
var leftDoc = id.value || '';
var rightDoc = id2.value || '';
var topSearch = (CM6 && typeof CM6.topSearchExtension === 'function') ? CM6.topSearchExtension() : null;
var extA = [CM6.baseExtensions(), CM6.themeExtension(isDark), CM6.placeholderExtension('<%:Edit original config...%>'), CM6.yaml(), CM6.yamlLinter(), CM6.lintGutter(), CM6.autocompletion({ override: [CM6.mihomoCompletion] }), CM6.indentUnit.of(" "), CM6.indentMarkerExtension()];
var extB = [CM6.baseExtensions(), CM6.themeExtension(isDark), CM6.placeholderExtension('<%:Runtime config (read only)%>'), CM6.yaml(), CM6.indentUnit.of(" "), CM6.indentMarkerExtension(), CM6.EditorState.readOnly.of(true)];
var mergeDefaults = CM6.mergeDefaultConfig || {};
if (topSearch) {
extA.push(topSearch);
extB.push(topSearch);
}
var mv = new CM6.MergeView({
a: { doc: leftDoc, extensions: extA },
b: { doc: rightDoc, extensions: extB },
parent: target,
diffConfig: mergeDefaults.diffConfig || { scanLimit: 5000 },
gutter: typeof mergeDefaults.gutter === 'boolean' ? mergeDefaults.gutter : true,
revertControls: mergeDefaults.revertControls || 'b-to-a',
highlightChanges: _mergeShowDifferences,
collapseUnchanged: typeof mergeDefaults.collapseUnchanged !== 'undefined' ? mergeDefaults.collapseUnchanged : false
});
if (readOnly) {
editor.setOption("readOnly","true");
var origDispatchA = mv.a.dispatch;
mv.a.dispatch = function(tr) {
origDispatchA.call(mv.a, tr);
if (tr.docChanged) id.value = mv.a.state.doc.toString();
};
if (wid && height) {
editor.setSize(wid, height);
};
};
mv.a.dom.style.width = wid;
mv.a.dom.style.height = height;
mv.b.dom.style.width = wid;
mv.b.dom.style.height = height;
}
function shell_editor(id, readOnly, wid, height)
{
var editor = CodeMirror.fromTextArea(id, {
mode: "shell",
autoRefresh: true,
styleActiveLine: true,
lineNumbers: true,
theme: "material",
lineWrapping: true,
matchBrackets: true,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
extraKeys: {
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function(cm) {
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
},
"Tab": function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add')
} else {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ")
cm.replaceSelection(spaces)
}
}
}
});
window._mergeViewInstance = mv;
_mergeShowDifferences = true;
}
if (wid && height) {
editor.setSize(wid, height);
};
};
var _cmWhenReady = function(cb) { cb(); };
function other_editor(id, readOnly, wid, height)
{
var editor = CodeMirror.fromTextArea(id, {
mode: "text/x-properties",
autoRefresh: true,
styleActiveLine: true,
lineNumbers: true,
theme: "material",
lineWrapping: true,
matchBrackets: true,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
extraKeys: {
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function(cm) {
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
},
"Tab": function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add')
} else {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ")
cm.replaceSelection(spaces)
}
}
}
});
if (wid && height) {
editor.setSize(wid, height);
};
};
function log_editor(id, name, readOnly, wid, height)
{
window['editor_' + name] = CodeMirror.fromTextArea(id, {
mode: "log",
autoRefresh: true,
styleActiveLine: true,
lineNumbers: true,
theme: "log",
lineWrapping: true,
matchBrackets: false,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
extraKeys: {
"F11": function(cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function(cm) {
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
}
}
});
if (readOnly) {
window['editor_' + name].setOption("readOnly","true");
};
if (wid && height) {
window['editor_' + name].setSize(wid, height);
};
if (isDarkBackground(document.body)) {
document.documentElement.setAttribute('data-darkmode', 'true');
};
};
_cmWhenReady(function() {
(function() {
CM6.startThemeObserver();
if (typeof isDarkBackground === 'function' && isDarkBackground(document.body)) {
document.documentElement.setAttribute('data-darkmode', 'true');
}
var core_log = document.getElementById("core_log");
var oc_log = document.getElementById("cbid.openclash.config.clog");
if (core_log && oc_log) {
log_editor(oc_log, 'oc', true, '100%', '540px');
log_editor(core_log, 'core', true, '100%', '540px');
};
if (oc_log) { log_editor(oc_log, 'oc', true, '100%', '540px'); }
if (core_log) { log_editor(core_log, 'core', true, '100%', '540px'); }
var custom_cfg_value = document.getElementById("cbid.openclash.<%=sid%>.other_parameters");
if (custom_cfg_value) {
editor(custom_cfg_value, false, '100%', '300px');
};
}
var custom_firewall = document.getElementById("cbid.openclash.config.firewall_custom");
if (custom_firewall) {
shell_editor(custom_firewall, false, "100%", '300px');
};
}
var myEditor_use = document.getElementById("cbid.table.1.user");
var myEditor_def = document.getElementById("cbid.table.1.default");
@@ -380,16 +327,16 @@ if (myEditor_use && myEditor_def) {
var myEditor_div_use = document.getElementById("cbi-table-1-user");
var myEditor_div_def = document.getElementById("cbi-table-1-default");
myEditor_div_def.parentNode.parentNode.style.cssText="text-align: left !important"
myEditor_div_def.parentNode.className='cbi-value';
myEditor_div_def.parentNode.style.display="revert"
myEditor_div_def.parentNode.style.width="100%"
myEditor_div_def.parentNode.parentNode.style.cssText = "text-align: left !important";
myEditor_div_def.parentNode.className = 'cbi-value';
myEditor_div_def.parentNode.style.display = "revert";
myEditor_div_def.parentNode.style.width = "100%";
myEditor_div_use.parentNode.className='cbi-value';
myEditor_div_use.parentNode.style.display="revert"
myEditor_div_use.parentNode.style.width="100%"
myEditor_div_use.parentNode.className = 'cbi-value';
myEditor_div_use.parentNode.style.display = "revert";
myEditor_div_use.parentNode.style.width = "100%";
merge_editor(myEditor_use, myEditor_def, myEditor_div_use, myEditor_div_def, true, false, 'auto', '700px');
};
}
var myEditor_hosts = document.getElementById("cbid.openclash.config.custom_hosts");
var myEditor_fall_fil = document.getElementById("cbid.openclash.config.custom_fallback_fil");
@@ -402,42 +349,18 @@ var myEditor_edit_file = document.getElementById("cbid.openclash.config.edit_fil
var myEditor_custom_sniffer = document.getElementById("cbid.openclash.config.sniffer_custom");
var myEditor_proxy_name_pol = document.getElementById("cbid.openclash.config.custom_proxy_server_dns_policy");
if (myEditor_hosts) {
editor(myEditor_hosts, false, '100%', '300px');
};
if (myEditor_edit_file) {
editor(myEditor_edit_file, false, '100%', '700px');
};
if (myEditor_fall_fil) {
editor(myEditor_fall_fil, false, '100%', '300px');
};
if (myEditor_name_pol) {
editor(myEditor_name_pol, false, '100%', '300px');
};
if (myEditor_proxy_name_pol) {
editor(myEditor_proxy_name_pol, false, '100%', '300px');
};
if (myEditor_hosts) { editor(myEditor_hosts, false, '100%', '300px'); }
if (myEditor_edit_file) { editor(myEditor_edit_file, false, '100%', '700px'); }
if (myEditor_fall_fil) { editor(myEditor_fall_fil, false, '100%', '300px'); }
if (myEditor_name_pol) { editor(myEditor_name_pol, false, '100%', '300px'); }
if (myEditor_proxy_name_pol) { editor(myEditor_proxy_name_pol, false, '100%', '300px'); }
if (myEditor_name_cus_r1) {
editor(myEditor_name_cus_r1, false, '100%', '300px');
editor(myEditor_name_cus_r2, false, '100%', '300px');
};
if (myEditor_fake_filter) {
other_editor(myEditor_fake_filter, false, '100%', '300px');
};
if (myEditor_custom_domain_dns) {
other_editor(myEditor_custom_domain_dns, false, '100%', '300px');
};
if (myEditor_custom_sniffer) {
other_editor(myEditor_custom_sniffer, false, '100%', '300px');
};
}
if (myEditor_fake_filter) { other_editor(myEditor_fake_filter, false, '100%', '300px'); }
if (myEditor_custom_domain_dns) { other_editor(myEditor_custom_domain_dns, false, '100%', '300px'); }
if (myEditor_custom_sniffer) { other_editor(myEditor_custom_sniffer, false, '100%', '300px'); }
var proxy_mg = document.getElementById('cbi-table-1-proxy_mg');
var rule_mg = document.getElementById('cbi-table-1-rule_mg');
@@ -446,12 +369,13 @@ var Apply = document.getElementById('cbi-table-1-Apply');
var Create = document.getElementById('cbi-table-1-Create');
if (proxy_mg) {
proxy_mg.style.textAlign="center";
rule_mg.style.textAlign="center";
Commit.style.textAlign="center";
Apply.style.textAlign="center";
Create.style.textAlign="center";
};
});
proxy_mg.style.textAlign = "center";
rule_mg.style.textAlign = "center";
Commit.style.textAlign = "center";
Apply.style.textAlign = "center";
Create.style.textAlign = "center";
}
})();
//]]>
</script>
@@ -355,12 +355,124 @@
</div>
<script type="text/javascript">
var SubscriptionUrlSetter = {
filename: '',
onSuccess: '',
show: function(filename, onSuccess) {
this.filename = filename;
this.onSuccess = onSuccess || '';
var overlay = document.getElementById('subscription-url-overlay');
var textarea = document.getElementById('subscription-url-textarea');
if (overlay && textarea) {
textarea.value = '';
overlay.style.display = 'flex';
textarea.focus();
this.bindEvents();
this.loadUrls();
}
},
hide: function() {
var overlay = document.getElementById('subscription-url-overlay');
if (overlay) {
overlay.style.display = 'none';
}
this.unbindEvents();
},
bindEvents: function() {
var textarea = document.getElementById('subscription-url-textarea');
if (textarea) {
textarea.addEventListener('keydown', this.handleKeyDown.bind(this));
}
},
unbindEvents: function() {
var textarea = document.getElementById('subscription-url-textarea');
if (textarea) {
textarea.removeEventListener('keydown', this.handleKeyDown.bind(this));
}
},
handleKeyDown: function(event) {
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
this.submit();
} else if (event.key === 'Escape') {
this.hide();
}
},
submit: function() {
var textarea = document.getElementById('subscription-url-textarea');
if (!textarea) return;
var urls = textarea.value.trim();
var urlList = urls.split('\n').map(function(url) {
return url.trim();
}).filter(function(url) {
return url !== '';
});
var newUrl = urlList.join('\n');
this.hide();
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "set_subinfo_url")%>', {
filename: this.filename,
url: newUrl
}, function(x, status) {
if (x && x.status == 200 && (status.info === "Success" || status.info === "Delete success")) {
if (SubscriptionUrlSetter.onSuccess) setTimeout(SubscriptionUrlSetter.onSuccess, 0);
} else {
alert('<%:Specify subscribe infos sources url failed:%>\n' + ((status && status.info) || (x && ('HTTP ' + x.status)) || '<%:Unknown error%>'));
}
});
},
handleSubURL: function(urlresult) {
var textarea = document.getElementById('subscription-url-textarea');
if (!textarea) return;
var urls = '';
if (urlresult.type && urlresult.type === "multiple") {
for (var data in urlresult.providers) {
urls += urlresult.providers[data].url + '#name=' + urlresult.providers[data].name + '\n';
}
}
if (urlresult.type && urlresult.type === "single") {
urls = urlresult.url;
}
textarea.value = urls;
},
loadUrls: function() {
var self = this;
var existingData = localStorage.getItem('sub_info_' + this.filename);
if (existingData) {
existingData = JSON.parse(existingData);
if (existingData.url_result) {
this.handleSubURL(existingData.url_result);
return;
}
}
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_subscribe_info_data")%>', {
filename: this.filename
}, function(x, status) {
if (x && x.status == 200 && status) {
self.handleSubURL(status);
}
});
}
};
var ConfigUploader = {
overlay: null,
model: null,
selectedFile: null,
isProcessing: false,
currentMode: 'file',
onSuccess: '',
_linkRe: /^(?:https?:\/\/\S+|[a-zA-Z]+:\/\/\S+|[^,\s]+,https?:\/\/\S+|[^%\s]+%2Chttps?%3A%2F%2F\S+)$/i,
init: function() {
@@ -604,13 +716,15 @@ var ConfigUploader = {
});
},
show: function() {
show: function(onSuccess) {
this.onSuccess = onSuccess || '';
this.overlay.classList.add('show');
document.getElementById('config-upload-title').textContent = '<%:Add Config%>';
this.reset();
},
showEditSubscribe: function(subscribeData, filename) {
showEditSubscribe: function(subscribeData, filename, onSuccess) {
this.onSuccess = onSuccess || '';
this.overlay.classList.add('show');
this.reset();
this.editFilename = filename;
@@ -1052,9 +1166,7 @@ var ConfigUploader = {
statusText.textContent = '<%:Upload successful%>';
setTimeout(function() {
self.hide();
if (typeof ConfigFileManager !== 'undefined' && ConfigFileManager.refreshConfigList) {
ConfigFileManager.refreshConfigList();
}
if (self.onSuccess) setTimeout(self.onSuccess, 0);
}, 2000);
return;
}
@@ -1099,9 +1211,7 @@ var ConfigUploader = {
setTimeout(function() {
self.hide();
if (typeof ConfigFileManager !== 'undefined' && ConfigFileManager.refreshConfigList) {
ConfigFileManager.refreshConfigList();
}
if (self.onSuccess) setTimeout(self.onSuccess, 0);
}, 2000);
} else {
throw new Error(data.message || '<%:Upload failed%>');
@@ -1281,9 +1391,7 @@ var ConfigUploader = {
setTimeout(function() {
self.hide();
if (typeof ConfigFileManager !== 'undefined' && ConfigFileManager.refreshConfigList) {
ConfigFileManager.refreshConfigList();
}
if (self.onSuccess) setTimeout(self.onSuccess, 0);
}, 2000);
} else {
self.handleError(this.isEditMode ? '<%:Failed to update subscription config%>' : '<%:Failed to download subscription config%>');
@@ -51,7 +51,7 @@ local dns_host = "www.instagram.com"
if (legend && output)
{
output.innerHTML =
'<img src="<%=resource%>/icons/loading.svg" onerror="this.onerror=null;this.src=\'<%=resource%>/icons/loading.gif\'" alt="<%:Loading%>" style="vertical-align:middle" /> ' +
'<img src="<%=resource%>/icons/loading.svg" onerror="this.onerror=null;this.src=\'<%=resource%>/icons/loading.gif\'" alt="<%:Loading...%>" style="vertical-align:middle" /> ' +
'<%:Waiting for command to complete...%>';
legend.textContent = '<%:Collecting data...%>';
@@ -95,7 +95,7 @@ local dns_host = "www.instagram.com"
if (legend && output)
{
output.innerHTML =
'<img src="<%=resource%>/icons/loading.svg" onerror="this.onerror=null;this.src=\'<%=resource%>/icons/loading.gif\'" alt="<%:Loading%>" style="vertical-align:middle" /> ' +
'<img src="<%=resource%>/icons/loading.svg" onerror="this.onerror=null;this.src=\'<%=resource%>/icons/loading.gif\'" alt="<%:Loading...%>" style="vertical-align:middle" /> ' +
'<%:Waiting for command to complete...%>';
legend.textContent = '<%:Collecting data...%>';
@@ -129,61 +129,20 @@ local dns_host = "www.instagram.com"
});
}
}
function gen_debug_logs()
{
var legend = document.getElementById('debug-rc-legend');
var output = document.getElementById('debug-rc-output');
if (legend && output)
{
output.innerHTML =
'<img src="<%=resource%>/icons/loading.svg" onerror="this.onerror=null;this.src=\'<%=resource%>/icons/loading.gif\'" alt="<%:Loading%>" style="vertical-align:middle" /> ' +
'<%:Waiting for command to complete...%>';
legend.textContent = '<%:Collecting data...%>';
legend.parentNode.style.display = 'block';
legend.style.display = 'block';
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "gen_debug_logs")%>', null, function(x, status) {
legend.textContent = '<%:Generated Logs%>';
if (x && x.status == 200 && x.responseText != "")
{
output.innerHTML = '';
var ta = document.createElement('textarea');
ta.style.width = '100%';
ta.value = x.responseText;
output.appendChild(ta);
_cmWhenReady(function() {
other_editor(ta, true, '100%', '400px');
});
}
else
{
output.innerHTML = '<span class="error"><%:Some error occurred!%></span>';
}
}
);
}
}
//]]></script>
<form>
<fieldset class="diag-style">
<div style="width:33%; float: left; text-align: center; white-space: nowrap;">
<div style="width:50%; float: left; text-align: center; white-space: nowrap;">
<%:Connection Test%>&nbsp;&nbsp;&nbsp;&nbsp;
<input type="text" value="<%=diag_host%>" name="diag" />
<input type="button" value="<%:Click to Test%>" class="btn cbi-button cbi-button-apply" onclick="update_status(this.form.diag)" />
</div>
<div style="width:33%; float: left; text-align: center; white-space: nowrap;">
<div style="width:50%; float: left; text-align: center; white-space: nowrap;">
<%:DNS Test%>&nbsp;&nbsp;&nbsp;&nbsp;
<input type="text" value="<%=dns_host%>" name="dns_host" />
<input type="button" value="<%:Click to Test%>" class="btn cbi-button cbi-button-apply" onclick="diag_dns(this.form.dns_host)" />
</div>
<div style="width:33%; float: left; text-align: center; white-space: nowrap;">
<%:Generate Logs%>&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" value="<%:Click to Generate%>" class="btn cbi-button cbi-button-apply" onclick="gen_debug_logs(this)" />
</div>
</fieldset>
<div class="diag-style" style="display:none">
@@ -195,9 +154,4 @@ local dns_host = "www.instagram.com"
<div id="dns-rc-legend" class="diag-legend"><%:Collecting data...%></div>
<span id="dns-rc-output"></span>
</div>
<div class="diag-style" style="display:none">
<div id="debug-rc-legend" class="diag-legend"><%:Collecting data...%></div>
<span id="debug-rc-output"></span>
</div>
</form>
+251 -27
View File
@@ -5,6 +5,7 @@
<ul class="cbi-tabmenu">
<li name="tab-header" class="cbi-tab"><a href="#"><%:OpenClash Log%></a></li>
<li name="tab-header" class="cbi-tab-disabled"><a href="#"><%:Core Log%></a></li>
<li name="tab-header" class="cbi-tab-disabled"><a href="#"><%:Debug Logs%></a></li>
</ul>
</div>
<div id="tab-content">
@@ -26,6 +27,13 @@
<label for="silent"><%:Silent%></label>
</div>
</div>
<div class="dom">
<textarea id="debug_log" class="cbi-input-textarea" style="width: 100%;display:none" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
<div id="debug-render-wrapper">
<div id="debug-rendered"></div>
<div class="oc-usage-help-float" id="debug-copy-source" onclick="copyDebugSource()" title="<%:Copy Debug%>"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></div>
</div>
</div>
</div>
</div>
@@ -35,6 +43,10 @@
<input type="button" class="btn cbi-button cbi-button-apply" id="start_refresh_button" value="<%:Start Refresh%>" onclick=" return start_refresh() "/>
<input type="button" class="btn cbi-button cbi-button-apply" id="del_log_button" value="<%:Clean%>" onclick=" return del_log() " />
<input type="button" class="btn cbi-button cbi-button-apply" id="down_log_button" value="<%:Download Log%>" onclick=" return download_log() " />
<span style="display:inline-flex; align-items:center; gap:4px;">
<input type="button" class="btn cbi-button cbi-button-apply" id="gen_debug_button" value="<%:Generate Logs%>" onclick="return gen_debug_logs()" />
<span id="debug_loading" style="display:none; vertical-align:middle;"><img src="<%=resource%>/icons/loading.svg" onerror="this.onerror=null;this.src='<%=resource%>/icons/loading.gif'" alt="<%:Loading...%>" style="vertical-align:middle" /></span>
</span>
</div>
</fieldset>
</body>
@@ -45,8 +57,10 @@ var s;
var log_len = 0;
var lv = document.getElementById('cbid.openclash.config.clog');
var cl = document.getElementById('core_log');
var dl = document.getElementById('debug_log');
var animatingOC = false;
var animatingCore = false;
var animatingDebug = false;
var coreWebSocket = null;
var coreLogBuffer = [];
var currentLogLevel = 'info';
@@ -116,6 +130,25 @@ function download_log(){
var dt = new Date();
var timestamp = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+"-"+dt.getHours()+"-"+dt.getMinutes()+"-"+dt.getSeconds();
var activeTabId = 0;
var titles = document.getElementsByName('tab-header');
for(var i=0; i<titles.length; i++){
if(titles[i].className === 'cbi-tab') {
activeTabId = i;
break;
}
}
var downloadContent = "";
if (activeTabId === 2) {
var debug_content = dl.value || '';
if (!debug_content.trim()) return;
downloadContent += debug_content;
createAndDownloadFile("OpenClash-Debug-"+timestamp+".log", downloadContent);
return;
}
var oc_content = "";
if (typeof editor_oc !== 'undefined' && editor_oc) {
oc_content = editor_oc.getValue();
@@ -125,6 +158,10 @@ function download_log(){
oc_content = lv.innerHTML;
}
oc_content = oc_content.split('\n').filter(function(line) {
return line.indexOf("】<%:Downloading URL%>【") === -1;
}).join('\n');
var core_content = "";
if (typeof editor_core !== 'undefined' && editor_core) {
core_content = editor_core.getValue();
@@ -134,15 +171,10 @@ function download_log(){
core_content = cl.innerHTML;
}
oc_content = oc_content.split('\n').filter(function(line) {
return line.indexOf("】<%:Downloading URL%>【") === -1;
}).join('\n');
if (!oc_content.trim() && !core_content.trim()) {
return;
}
var downloadContent = "";
if (oc_content.trim()) {
downloadContent += "<%:OpenClash Log%>:\n" + oc_content + "\n\n";
}
@@ -155,16 +187,46 @@ function download_log(){
};
function del_log() {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>',null,function(x, data){
lv.innerHTML="";
cl.innerHTML="";
coreLogBuffer = [];
log_len = 0;
editor_oc.setValue(lv.value);
editor_core.setValue(cl.value);
editor_core.refresh();
editor_oc.refresh();
});
var activeTabId = 0;
var titles = document.getElementsByName('tab-header');
for(var i=0; i<titles.length; i++){
if(titles[i].className === 'cbi-tab') {
activeTabId = i;
break;
}
}
if (activeTabId === 2) {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>', {type: "debug"}, function(x, data){
dl.value = "";
var wrapper = document.getElementById('debug-render-wrapper');
var rendered = document.getElementById('debug-rendered');
if (wrapper) { wrapper.style.display = 'none'; }
if (rendered) { rendered.innerHTML = ''; }
if (typeof editor_debug !== 'undefined' && editor_debug) {
editor_debug.setValue("");
if (editor_debug.dom) {
editor_debug.dom.style.setProperty('display', '', 'important');
}
editor_debug.refresh();
} else if (typeof markdown_editor === 'function' && dl) {
markdown_editor(dl, 'debug', true, '100%', '540px');
}
});
} else {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>', null, function(x, data){
lv.innerHTML="";
cl.innerHTML="";
coreLogBuffer = [];
log_len = 0;
if (typeof editor_oc !== 'undefined' && editor_oc) {
editor_oc.setValue(lv.value);
}
if (typeof editor_core !== 'undefined' && editor_core) {
editor_core.setValue(cl.value);
}
});
}
return
};
@@ -281,6 +343,44 @@ function coreLogWebSocket() {
});
}
function gen_debug_logs()
{
var loading_el = document.getElementById('debug_loading');
var btn = document.getElementById('gen_debug_button');
var originalText = btn.value;
if (loading_el) { loading_el.style.display = 'inline'; }
if (btn) { btn.value = '<%:Generating...%>'; btn.disabled = true; }
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "gen_debug_logs")%>', null, function(x, status) {
if (loading_el) { loading_el.style.display = 'none'; }
if (btn) { btn.value = originalText; btn.disabled = false; }
dl.value = x.responseText || '<%:Some error occurred!%>';
if (typeof editor_debug !== 'undefined' && editor_debug) {
editor_debug.setValue(dl.value);
}
renderDebugView();
});
return;
};
function load_existing_debug_log()
{
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_debug_logs")%>', null, function(x, status) {
if (x && x.status == 200 && x.responseText != "")
{
dl.value = x.responseText;
renderDebugView();
}
else
{
if (typeof markdown_editor === 'function' && dl) {
markdown_editor(dl, 'debug', true, '100%', '540px');
}
}
});
};
function line_tolocal(str) {
var trans_local = new Array();
var local_count = 0;
@@ -657,6 +757,12 @@ window.onload = function(){
var titles = document.getElementsByName('tab-header');
var divs = document.getElementsByClassName('dom');
if(titles.length != divs.length) return;
var tc = document.getElementById('tab-content');
if (tc) tc.style.position = 'relative';
divs[0].classList.add('active');
for(var i=0; i<titles.length; i++){
var li = titles[i];
li.id = i;
@@ -665,20 +771,10 @@ window.onload = function(){
if (tab.className === 'cbi-tab') return;
for(var j=0; j<titles.length; j++){
titles[j].className = 'cbi-tab-disabled';
divs[j].style.display = 'none';
divs[j].classList.remove('active');
}
tab.className = 'cbi-tab';
divs[tab.id].style.display = 'block';
if(tab.id == 0 && typeof editor_oc !== 'undefined') {
setTimeout(function(){
editor_oc.refresh();
}, 10);
} else if(tab.id == 1 && typeof editor_core !== 'undefined') {
setTimeout(function(){
editor_core.refresh();
}, 10);
}
divs[tab.id].classList.add('active');
};
}
@@ -687,7 +783,135 @@ window.onload = function(){
}
get_log_level();
poll_log();
setTimeout(function() {
load_existing_debug_log();
}, 500);
};
function renderDebugView() {
var wrapper = document.getElementById('debug-render-wrapper');
var rendered = document.getElementById('debug-rendered');
if (!wrapper || !rendered) return;
var src = '';
if (typeof editor_debug !== 'undefined' && editor_debug) {
src = editor_debug.getValue();
} else if (dl) {
src = dl.value || '';
}
if (!src) return;
if (typeof editor_debug !== 'undefined' && editor_debug && editor_debug.dom) {
editor_debug.dom.style.setProperty('display', 'none', 'important');
}
var cms = dl.parentNode.querySelectorAll('.cm-editor');
for (var i = 0; i < cms.length; i++) {
cms[i].style.setProperty('display', 'none', 'important');
}
if (typeof CM6 !== 'undefined' && CM6.renderMarkdown) {
rendered.innerHTML = CM6.renderMarkdown(src);
} else {
rendered.innerHTML = src.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g,'<br>');
}
var pres = rendered.querySelectorAll('pre');
for (var i = 0; i < pres.length; i++) {
(function(pre) {
if (pre.parentNode && pre.parentNode.classList.contains('pre-copy-wrap')) return;
var copyIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
var checkIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
var btn = document.createElement('div');
btn.className = 'pre-copy-btn';
btn.title = '<%:Copy%>';
btn.innerHTML = copyIcon;
btn.onclick = function(e) {
e.stopPropagation();
var text = pre.textContent || '';
var done = function() {
btn.innerHTML = checkIcon;
setTimeout(function() { btn.innerHTML = copyIcon; }, 1200);
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(done).catch(function() {
var ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed'; ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
done();
});
} else {
var ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed'; ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
done();
}
};
var wrap = document.createElement('div');
wrap.className = 'pre-copy-wrap';
pre.parentNode.insertBefore(wrap, pre);
wrap.appendChild(pre);
wrap.appendChild(btn);
})(pres[i]);
}
wrapper.style.display = 'block';
dl.style.display = 'none';
if (dl.parentNode && dl.parentNode.className.indexOf('oc') < 0) {
dl.parentNode.classList.add('oc');
}
if (typeof isDarkBackground === 'function' && isDarkBackground(document.body)) {
dl.parentNode.setAttribute('data-darkmode', 'true');
} else {
dl.parentNode.removeAttribute('data-darkmode');
}
}
function copyDebugSource() {
var src = '';
if (typeof editor_debug !== 'undefined' && editor_debug) {
src = editor_debug.getValue();
} else if (dl) {
src = dl.value || '';
}
if (!src) return;
var done = function() {
var btn = document.getElementById('debug-copy-source');
if (btn) {
var orig = btn.innerHTML;
btn.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
setTimeout(function() { btn.innerHTML = orig; }, 1500);
}
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(src).then(done).catch(function() {
var ta = document.createElement('textarea');
ta.value = src;
ta.style.position = 'fixed'; ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
done();
});
} else {
var ta = document.createElement('textarea');
ta.value = src;
ta.style.position = 'fixed'; ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
done();
}
}
//]]>
</script>
<%+cbi/valuefooter%>
@@ -365,7 +365,7 @@
</svg>
</div>
<script src="/luci-static/resources/openclash/js/common.js"></script>
<script src="/luci-static/resources/openclash/js/common.js?v=<%=plugin_version%>"></script>
<script type="text/javascript">//<![CDATA[
var DOMCache = {
clash: document.getElementById('_clash'),
@@ -1808,121 +1808,6 @@
}
};
var SubscriptionUrlSetter = {
filename: '',
show: function(filename) {
this.filename = filename;
var overlay = document.getElementById('subscription-url-overlay');
var textarea = document.getElementById('subscription-url-textarea');
if (overlay && textarea) {
textarea.value = '';
overlay.style.display = 'flex';
textarea.focus();
this.bindEvents();
this.loadUrls();
}
},
hide: function() {
var overlay = document.getElementById('subscription-url-overlay');
if (overlay) {
overlay.style.display = 'none';
}
this.unbindEvents();
},
bindEvents: function() {
var textarea = document.getElementById('subscription-url-textarea');
if (textarea) {
textarea.addEventListener('keydown', this.handleKeyDown.bind(this));
}
},
unbindEvents: function() {
var textarea = document.getElementById('subscription-url-textarea');
if (textarea) {
textarea.removeEventListener('keydown', this.handleKeyDown.bind(this));
}
},
handleKeyDown: function(event) {
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
this.submit();
} else if (event.key === 'Escape') {
this.hide();
}
},
submit: function() {
var textarea = document.getElementById('subscription-url-textarea');
if (!textarea) return;
var urls = textarea.value.trim();
var urlList = urls.split('\n').map(function(url) {
return url.trim();
}).filter(function(url) {
return url !== '';
});
var newUrl = urlList.join('\n');
this.hide();
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "set_subinfo_url")%>', {
filename: this.filename,
url: newUrl
}, function(x, status) {
if (x && x.status == 200 && status.info === "Success") {
refreshSubscriptionInfo();
} else if (x && x.status == 200 && status.info === "Delete success") {
refreshSubscriptionInfo();
} else {
alert('<%:Specify subscribe infos sources url failed:%>\n' + (status.info || '<%:Unknown error%>'));
}
});
},
handleSubURL: function(urlresult) {
var textarea = document.getElementById('subscription-url-textarea');
if (!textarea) return;
var urls = '';
if (urlresult.type && urlresult.type === "multiple") {
for (var data in urlresult.providers) {
urls += urlresult.providers[data].url + '#name=' + urlresult.providers[data].name + '\n';
}
}
if (urlresult.type && urlresult.type === "single") {
urls = urlresult.url;
}
textarea.value = urls;
},
loadUrls: function() {
var self = this;
var existingData = localStorage.getItem('sub_info_' + this.filename);
if (existingData) {
existingData = JSON.parse(existingData);
if (existingData.url_result) {
this.handleSubURL(existingData.url_result);
return;
}
};
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_subscribe_info_data")%>', {
filename: this.filename
}, function(x, status) {
if (x && x.status == 200 && status) {
self.handleSubURL(status);
}
});
}
};
var OverwriteSubscribeManager = {
container: null,
data: null,
@@ -3666,7 +3551,7 @@
}
function wikipage() {
url5 = 'https://github.com/vernesong/OpenClash/wiki';
url5 = 'https://github.com/vernesong/OpenClash/blob/dev/.github/skills/openclash-user-guide/SKILL.md';
winOpen(url5);
}
@@ -4269,17 +4154,17 @@
return false;
}
SubscriptionUrlSetter.show(filename);
SubscriptionUrlSetter.show(filename, "refreshSubscriptionInfo()");
return false;
}
function uploadConfig() {
if (typeof ConfigUploader !== 'undefined' && ConfigUploader.show) {
ConfigUploader.show();
ConfigUploader.show("ConfigFileManager.refreshConfigList()");
} else {
setTimeout(function() {
if (typeof ConfigUploader !== 'undefined' && ConfigUploader.show) {
ConfigUploader.show();
ConfigUploader.show("ConfigFileManager.refreshConfigList()");
} else {
alert('<%:Config editor not ready, please try again%>');
}
@@ -4307,11 +4192,11 @@
}, function(x, status) {
if (x.status == 200) {
if (ConfigUploader && ConfigUploader.showEditSubscribe) {
ConfigUploader.showEditSubscribe(status, filename);
ConfigUploader.showEditSubscribe(status, filename, "ConfigFileManager.refreshConfigList()");
} else {
setTimeout(function() {
if (ConfigUploader && ConfigUploader.showEditSubscribe) {
ConfigUploader.showEditSubscribe(status, filename);
ConfigUploader.showEditSubscribe(status, filename, "ConfigFileManager.refreshConfigList()");
} else {
alert('<%:Config editor not ready, please try again%>');
}
@@ -14,7 +14,7 @@
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg>
</button>
<button type="button" class="sub_setting" title='<%:Specify URL%>' alt='<%:Specify URL%>' onclick='return set_subinfo_url_<%=idname%>(this,"<%=filename%>")'>
<button type="button" class="sub_setting" title='<%:Specify URL%>' alt='<%:Specify URL%>' onclick='return setUrlConfig_<%=idname%>()'>
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="4">
<path d="M4 6H44V36H29L24 41L19 36H4V6Z"/>
<path d="M23 21H25.0025" />
@@ -22,6 +22,12 @@
<path d="M13.001 21H14.9999"/>
</svg>
</button>
<button type="button" class="sub_setting" title='<%:Edit Subscription%>' alt='<%:Edit Subscription%>' onclick='return uploadConfig_<%=idname%>()'>
<svg width="14" height="14" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.2838 43.1713C14.9327 42.1736 11.9498 40.3213 9.58787 37.867C10.469 36.8227 11 35.4734 11 34.0001C11 30.6864 8.31371 28.0001 5 28.0001C4.79955 28.0001 4.60139 28.01 4.40599 28.0292C4.13979 26.7277 4 25.3803 4 24.0001C4 21.9095 4.32077 19.8938 4.91579 17.9995C4.94381 17.9999 4.97188 18.0001 5 18.0001C8.31371 18.0001 11 15.3138 11 12.0001C11 11.0488 10.7786 10.1493 10.3846 9.35011C12.6975 7.1995 15.5205 5.59002 18.6521 4.72314C19.6444 6.66819 21.6667 8.00013 24 8.00013C26.3333 8.00013 28.3556 6.66819 29.3479 4.72314C32.4795 5.59002 35.3025 7.1995 37.6154 9.35011C37.2214 10.1493 37 11.0488 37 12.0001C37 15.3138 39.6863 18.0001 43 18.0001C43.0281 18.0001 43.0562 17.9999 43.0842 17.9995C43.6792 19.8938 44 21.9095 44 24.0001C44 25.3803 43.8602 26.7277 43.594 28.0292C43.3986 28.01 43.2005 28.0001 43 28.0001C39.6863 28.0001 37 30.6864 37 34.0001C37 35.4734 37.531 36.8227 38.4121 37.867C36.0502 40.3213 33.0673 42.1736 29.7162 43.1713C28.9428 40.752 26.676 39.0001 24 39.0001C21.324 39.0001 19.0572 40.752 18.2838 43.1713Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"/>
<path d="M24 31C27.866 31 31 27.866 31 24C31 20.134 27.866 17 24 17C20.134 17 17 20.134 17 24C17 27.866 20.134 31 24 31Z" fill="none" stroke="currentColor" stroke-width="4" stroke-linejoin="round"/>
</svg>
</button>
</div>
<script type="text/javascript">//<![CDATA[
@@ -50,24 +56,24 @@ function initDarkMode() {
function progressbar_<%=idname%>(v, m, pc, np, f, t, tr) {
var screenWidth = window.innerWidth || document.documentElement.clientWidth;
var fontSize = '12px';
var minWidth = '220px';
var minWidth = '200px';
var topPosition = tr == "null" ? '6px' : '2px';
if (screenWidth <= 320) {
fontSize = '8px';
minWidth = '160px';
minWidth = '140px';
topPosition = tr == "null" ? '8px' : '4px';
} else if (screenWidth <= 480) {
fontSize = '9px';
minWidth = '180px';
minWidth = '160px';
topPosition = tr == "null" ? '7px' : '3px';
} else if (screenWidth <= 768) {
fontSize = '10px';
minWidth = '200px';
minWidth = '180px';
topPosition = tr == "null" ? '6px' : '3px';
} else if (screenWidth <= 1024) {
fontSize = '11px';
minWidth = '220px';
minWidth = '200px';
topPosition = tr == "null" ? '6px' : '2px';
}
@@ -282,139 +288,27 @@ function sub_info_refresh_<%=idname%>(force) {
});
};
function set_subinfo_url_<%=idname%>(btn, filename) {
if (filename == null || filename == "") {
return false;
}
function setUrlConfig_<%=idname%>() {
SubscriptionUrlSetter.show("<%=filename%>", "sub_info_refresh_<%=idname%>(true)");
return false;
}
var dialogDiv = document.createElement('div');
dialogDiv.className = 'config-upload-model-overlay show';
function uploadConfig_<%=idname%>() {
if (typeof ConfigUploader === 'undefined') return false;
var contentDiv = document.createElement('div');
contentDiv.className = 'config-upload-model';
var headerDiv = document.createElement('div');
headerDiv.className = 'config-upload-header';
var titleDiv = document.createElement('div');
titleDiv.className = 'config-upload-title';
titleDiv.innerHTML = '<%:Set Subscription Info URL%>';
headerDiv.appendChild(titleDiv);
var closeBtn = document.createElement('button');
closeBtn.className = 'icon-btn';
closeBtn.type = 'button';
closeBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
closeBtn.onclick = function() {
document.body.removeChild(portal);
};
headerDiv.appendChild(closeBtn);
var bodyDiv = document.createElement('div');
bodyDiv.className = 'config-upload-content';
var formGroup = document.createElement('div');
formGroup.className = 'form-group';
var label = document.createElement('label');
label.className = 'highlight-label';
label.innerHTML = '<%:Paste the new url of subscribe infos sources here:%>';
formGroup.appendChild(label);
var textarea = document.createElement('textarea');
textarea.className = 'form-textarea';
textarea.placeholder = '<%:Enter URLs, one per line, use #name=example end for specifing display name%> (https://example.com#name=example)';
formGroup.appendChild(textarea);
bodyDiv.appendChild(formGroup);
var footerDiv = document.createElement('div');
footerDiv.className = 'config-upload-footer';
var statusDiv = document.createElement('div');
statusDiv.className = 'config-upload-status';
footerDiv.appendChild(statusDiv);
var buttonsDiv = document.createElement('div');
buttonsDiv.className = 'config-upload-buttons';
var cancelBtn = document.createElement('button');
cancelBtn.className = 'btn cancel-btn';
cancelBtn.type = 'button';
cancelBtn.innerHTML = '<%:Cancel%>';
var confirmBtn = document.createElement('button');
confirmBtn.className = 'btn upload-btn';
confirmBtn.type = 'button';
confirmBtn.innerHTML = '<%:Submit%>';
confirmBtn.onclick = function() {
var new_url = textarea.value.trim();
document.body.removeChild(portal);
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "set_subinfo_url")%>', {filename: filename, url: new_url}, function(x, status) {
if (x && x.status == 200 && status.info == "Success") {
sub_info_refresh_<%=idname%>(true);
alert("<%:Specify subscribe infos sources url successfully!%>");
} else if (x && x.status == 200 && status.info == "Delete success") {
sub_info_refresh_<%=idname%>(true);
alert("<%:Delete Specify Subscribe infos sources url successfully!%>");
} else {
alert("<%:Specify subscribe infos sources url failed:%>\n" + status.info);
}
});
};
cancelBtn.onclick = function() {
document.body.removeChild(portal);
};
buttonsDiv.appendChild(cancelBtn);
buttonsDiv.appendChild(confirmBtn);
footerDiv.appendChild(buttonsDiv);
contentDiv.appendChild(headerDiv);
contentDiv.appendChild(bodyDiv);
contentDiv.appendChild(footerDiv);
dialogDiv.appendChild(contentDiv);
var portal = document.createElement('div');
portal.className = 'oc';
portal.appendChild(dialogDiv);
document.body.appendChild(portal);
textarea.focus();
var handleSubURL = function(urlresult) {
var urls = '';
if (urlresult.type && urlresult.type === "multiple") {
for (var data in urlresult.providers) {
urls += urlresult.providers[data].url + '#name=' + urlresult.providers[data].name + '\n';
}
}
if (urlresult.type && urlresult.type === "single") {
urls = urlresult.url;
}
textarea.value = urls;
};
var existingData = localStorage.getItem('sub_info_' + filename);
if (existingData) {
existingData = JSON.parse(existingData);
if (existingData.url_result) {
handleSubURL(existingData.url_result);
return;
}
};
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_subscribe_info_data")%>', {
var filename = "<%=filename%>";
var cb = "sub_info_refresh_<%=idname%>(true)";
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_subscribe_data")%>', {
filename: filename
}, function(x, status) {
if (x && x.status == 200 && status) {
handleSubURL(status);
if (ConfigUploader.showEditSubscribe) {
ConfigUploader.showEditSubscribe((x && x.status == 200) ? status : null, filename, cb);
} else {
ConfigUploader.show(cb);
}
});
};
return false;
}
//]]></script>
<%+cbi/valuefooter%>
@@ -2,6 +2,7 @@
local rowcnt = 1
local uci = require("luci.model.uci").cursor()
local fs = require "luci.openclash"
local plugin_version = fs.oc_version()
function rowstyle()
rowcnt = rowcnt + 1
@@ -446,7 +447,7 @@ local sectiontype = "_"..self.config.."_"..string.match(self.sectiontype, "[%w_]
</fieldset>
<!-- /tblsection -->
<script src="/luci-static/resources/openclash/js/common.js"></script>
<script src="/luci-static/resources/openclash/js/common.js?v=<%=plugin_version%>"></script>
<script type="text/javascript">//<![CDATA[
window.addEventListener('load', onload<%=sectiontype%>, false);
@@ -16,7 +16,7 @@
</span>
</li>
<script src="/luci-static/resources/openclash/js/common.js"></script>
<script src="/luci-static/resources/openclash/js/common.js?v=<%=plugin_version%>"></script>
<script type="text/javascript">//<![CDATA[
var config_name = document.getElementById('cfg_name');
+28 -7
View File
@@ -95,12 +95,12 @@ msgstr "No configurado"
msgid "Server Logs"
msgstr "Registros del servidor"
msgid "Core Tests"
msgstr "Prueba del núcleo"
msgid "Debug Logs"
msgstr "Registros de depuración"
msgid "Generate Logs"
msgstr "Generar registros"
msgid "Generated Logs"
msgstr "Registros generados"
@@ -1464,6 +1464,9 @@ msgstr "Tipo de protocolo no soportado"
msgid "Copy"
msgstr "Copiar"
msgid "Copy Debug"
msgstr "Copiar Depuración"
msgid "Export"
msgstr "Exportar configuración"
@@ -2841,11 +2844,11 @@ msgstr "Si la descarga falla, prueba a configurar un CDN en Sobrescritura → Ge
msgid "Used for Downloading Subscriptions, Defaults to"
msgstr "User-Agent usado para descargar suscripciones, por defecto:"
msgid "Set Proxies Address Skip Failed,"
msgstr "Fallo al configurar la omisión de direcciones de proxy,"
msgid "Set Proxies Address Skip: Bypass"
msgstr "Configurar omisión de direcciones proxy: Omitido"
msgid "Age decrypt failed,"
msgstr "Error al descifrar con Age para,"
msgid "Set Proxies Address Skip: Failed"
msgstr "Configurar omisión de direcciones proxy: Fallido"
msgid "Failed to parse config file with Lua helper"
msgstr "Error al analizar el archivo de configuración con el auxiliar Lua"
@@ -3279,6 +3282,9 @@ msgstr "El nombre del archivo contiene caracteres no válidos"
msgid "Uploading..."
msgstr "Subiendo..."
msgid "Generating..."
msgstr "Generando..."
msgid "Upload completed"
msgstr "Subida completada"
@@ -3822,6 +3828,21 @@ msgstr "Fallo al ejecutar el script de sobrescritura personalizado,"
msgid "Load YAML Override Block"
msgstr "Cargar bloque de sobrescritura YAML"
msgid "Enter YAML configuration..."
msgstr "Ingrese configuración YAML..."
msgid "Enter shell script..."
msgstr "Ingrese script de shell..."
msgid "Enter configuration..."
msgstr "Ingrese configuración..."
msgid "Edit original config..."
msgstr "Editar configuración original..."
msgid "Runtime config (read only)"
msgstr "Configuración en ejecución (solo lectura)"
msgid "Invalid YAML Override format, skipped..."
msgstr "Formato de sobrescritura YAML no válido, omitido..."
+28 -7
View File
@@ -95,6 +95,9 @@ msgstr "未设置"
msgid "Server Logs"
msgstr "运行日志"
msgid "Core Tests"
msgstr "内核测试"
msgid "Debug Logs"
msgstr "调试日志"
@@ -104,9 +107,6 @@ msgstr "生成日志"
msgid "Generated Logs"
msgstr "日志生成结果"
msgid "Click to Generate"
msgstr "点击生成"
msgid "Enable OpenClash"
msgstr "启动 OpenClash"
@@ -1464,6 +1464,9 @@ msgstr "不支持的协议"
msgid "Copy"
msgstr "复制"
msgid "Copy Debug"
msgstr "复制调试日志"
msgid "Export"
msgstr "导出配置信息"
@@ -2847,11 +2850,11 @@ msgstr "如果下载失败,您可以尝试在覆写设置 - 常规设置 - Git
msgid "Used for Downloading Subscriptions, Defaults to"
msgstr "用于下载订阅时指定 UA,默认为"
msgid "Set Proxies Address Skip Failed,"
msgstr "绕过代理服务器地址设置失败,"
msgid "Set Proxies Address Skip: Bypass"
msgstr "绕过代理服务器地址设置:跳过"
msgid "Age decrypt failed,"
msgstr "绕过代理服务器地址 Age 解密失败,"
msgid "Set Proxies Address Skip: Failed"
msgstr "绕过代理服务器地址设置:失败"
msgid "Failed to parse config file with Lua helper"
msgstr "绕过代理服务器地址解析失败"
@@ -3294,6 +3297,9 @@ msgstr "文件名包含无效字符"
msgid "Uploading..."
msgstr "上传中..."
msgid "Generating..."
msgstr "生成中..."
msgid "Upload completed"
msgstr "上传完成"
@@ -3822,6 +3828,21 @@ msgstr "用户"
msgid "Serial Number"
msgstr "序号"
msgid "Enter YAML configuration..."
msgstr "请输入 YAML 配置..."
msgid "Enter shell script..."
msgstr "请输入 Shell 脚本..."
msgid "Enter configuration..."
msgstr "请输入配置..."
msgid "Edit original config..."
msgstr "编辑原始配置..."
msgid "Runtime config (read only)"
msgstr "运行配置(只读)"
msgid "Set Custom Overwrite Script Failed,"
msgstr "自定义覆写命令执行失败,"
+27 -17
View File
@@ -1499,8 +1499,10 @@ if [ -n "$FW4" ]; then
if [ "$disable_udp_quic" -eq 1 ]; then
if [ "$china_ip_route" = "2" ]; then
nft insert rule inet fw4 input position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
else
nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
fi
fi
fi
@@ -1646,9 +1648,11 @@ if [ -n "$FW4" ]; then
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
if [ "$china_ip_route" = "2" ]; then
nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 input position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
else
nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\"
fi
fi
fi
@@ -1971,17 +1975,17 @@ if [ -n "$FW4" ]; then
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
chain="forward"
else
chain="input"
fi
if [ "$china_ip6_route" = "2" ]; then
rule="ip6 daddr @china_ip6_route"
else
rule="ip6 daddr != @china_ip6_route"
fi
nft insert rule inet fw4 $chain position 0 udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\"
nft insert rule inet fw4 input position 0 udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\"
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\"
else
nft insert rule inet fw4 forward position 0 udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\"
fi
fi
#bypass gateway compatible
@@ -2365,8 +2369,10 @@ if [ -z "$FW4" ]; then
if [ "$disable_udp_quic" -eq 1 ]; then
if [ "$china_ip_route" = "2" ]; then
iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT
iptables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT
else
iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT
iptables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT
fi
fi
fi
@@ -2502,9 +2508,11 @@ if [ -z "$FW4" ]; then
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
if [ "$china_ip_route" = "2" ]; then
iptables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT
iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT
iptables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT
else
iptables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT
iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT
iptables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT
fi
fi
fi
@@ -2821,17 +2829,17 @@ if [ -z "$FW4" ]; then
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
chain="FORWARD -o utun"
else
chain="INPUT"
fi
if [ "$china_ip6_route" = "2" ]; then
rule="-m set --match-set china_ip6_route dst"
else
rule="-m set ! --match-set china_ip6_route dst"
fi
ip6tables -I $chain -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT
ip6tables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
ip6tables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT
else
ip6tables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT
fi
fi
#bypass gateway compatible
@@ -3727,7 +3735,9 @@ stop_service()
procd_running "openclash" >/dev/null && sleep 1 || break
done
if procd_running "openclash" >/dev/null; then
kill -9 $(pidof clash) 2>/dev/null || true
for pid in $(pidof clash 2>/dev/null); do
kill -9 "$pid" 2>/dev/null || true
done
fi
LOG_OUT "Step 4: Restart Dnsmasq..."
@@ -148,6 +148,8 @@ module YAML
end
def self.decode64(input)
first_line = input.each_line.find { |l| !l.strip.empty? } || ""
return input if !first_line.strip.match?(/\A[A-Za-z0-9+\/=]+\z/)
out, status = popen_stream(["base64", "-d"], input)
status.success? ? out : input
rescue Errno::ENOENT
@@ -101,7 +101,7 @@ ts_re()
if [ -z "$1" ]; then
echo "未安装"
else
echo "已安装"
echo "已安装 ($1)"
fi
}
@@ -116,296 +116,380 @@ dns_re()
fi
}
echo "OpenClash 调试日志" > "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
ipv6_mode_name()
{
case "$1" in
0) echo "TProxy 模式" ;;
1) echo "Redirect 模式" ;;
2) echo "TUN 模式" ;;
3) echo "Mix 混合模式" ;;
*) echo "未知" ;;
esac
}
生成时间: $LOGTIME
插件版本: $op_version
隐私提示: 上传此日志前请注意检查、屏蔽公网IP、节点、密码等相关敏感信息
cat > "$DEBUG_LOG" <<-EOF
# OpenClash 调试日志
> 生成时间: $LOGTIME
> 插件版本: ${op_version:-未知}
> 隐私提示: 上传此日志前请注意检查、屏蔽公网IP、节点、密码等相关敏感信息
## 系统信息
| 项目 | 值 |
|------|----|
| 主机型号 | $(cat /tmp/sysinfo/model 2>/dev/null) |
| 固件版本 | $(cat /usr/lib/os-release 2>/dev/null |grep OPENWRT_RELEASE 2>/dev/null |awk -F '"' '{print $2}' 2>/dev/null) |
| LuCI版本 | $(ipk_v "luci") |
| 内核版本 | $(uname -r 2>/dev/null) |
| 处理器架构 | $cpu_model |
| 系统运行时间 | $(uptime 2>/dev/null) |
| IPV6-DHCP | $(uci -q get dhcp.lan.dhcpv6 || echo "未配置") |
| DNS劫持 | $(dns_re "$enable_redirect_dns") |
### 磁盘与内存
\`\`\`bash
# df -h / /tmp /etc/openclash
$(df -h / /tmp /etc/openclash 2>/dev/null)
\`\`\`
\`\`\`bash
# free -m
$(free -m 2>/dev/null)
\`\`\`
\`\`\`bash
# cat /proc/meminfo | grep -E '^(MemTotal|MemAvailable|SwapTotal|SwapFree)'
$(cat /proc/meminfo 2>/dev/null | grep -E '^(MemTotal|MemAvailable|SwapTotal|SwapFree)')
\`\`\`
### Dnsmasq 配置
\`\`\`bash
# uci show dhcp.@dnsmasq[0]
$(uci show dhcp.@dnsmasq[0] 2>/dev/null)
\`\`\`
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== 系统信息 =====================#
## 依赖检查
主机型号: $(cat /tmp/sysinfo/model 2>/dev/null)
固件版本: $(cat /usr/lib/os-release 2>/dev/null |grep OPENWRT_RELEASE 2>/dev/null |awk -F '"' '{print $2}' 2>/dev/null)
LuCI版本: $(ipk_v "luci")
内核版本: $(uname -r 2>/dev/null)
处理器架构: $cpu_model
系统运行时间: $(uptime 2>/dev/null)
#磁盘与内存
$(df -h / /tmp /etc/openclash 2>/dev/null)
$(free -m 2>/dev/null)
$(cat /proc/meminfo 2>/dev/null | grep -E '^(MemTotal|MemAvailable|SwapTotal|SwapFree)')
#此项有值时,如不使用IPv6,建议到网络-接口-lan的设置中禁用IPV6的DHCP
IPV6-DHCP: $(uci -q get dhcp.lan.dhcpv6)
DNS劫持: $(dns_re "$enable_redirect_dns")
#DNS劫持为Dnsmasq时,此项结果应仅有配置文件的DNS监听地址
Dnsmasq转发设置: $(uci -q get dhcp.@dnsmasq[0].server)
Dnsmasq完整配置:
$(uci show dhcp.@dnsmasq[0] 2>/dev/null)
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== 依赖检查 =====================#
dnsmasq-full: $(ts_re "$(ipk_v "dnsmasq-full")")
dnsmasq-full(ipset): $(ts_re "$(dnsmasq --version |grep -v no-ipset |grep ipset)")
dnsmasq-full(nftset): $(ts_re "$(dnsmasq --version |grep nftset)")
bash: $(ts_re "$(ipk_v "bash")")
curl: $(ts_re "$(ipk_v "curl")")
ca-bundle: $(ts_re "$(ipk_v "ca-bundle")")
ipset: $(ts_re "$(ipk_v "ipset")")
ip-full: $(ts_re "$(ipk_v "ip-full")")
ruby: $(ts_re "$(ipk_v "ruby")")
ruby-yaml: $(ts_re "$(ipk_v "ruby-yaml")")
ruby-psych: $(ts_re "$(ipk_v "ruby-psych")")
ruby-pstore: $(ts_re "$(ipk_v "ruby-pstore")")
ruby版本: $(ruby --version 2>/dev/null || echo "未安装")
ruby功能测试: $(ruby -e "require 'yaml'; YAML.load('test: ok'); puts '正常'" 2>/dev/null || echo "异常")
kmod-tun(TUN模式): $(ts_re "$(ipk_v "kmod-tun")")
luci-compat(Luci >= 19.07): $(ts_re "$(ipk_v "luci-compat")")
kmod-inet-diag(PROCESS-NAME): $(ts_re "$(ipk_v "kmod-inet-diag")")
unzip: $(ts_re "$(ipk_v "unzip")")
| 依赖 | 状态 |
|------|------|
| dnsmasq-full | $(ts_re "$(ipk_v "dnsmasq-full")") |
| dnsmasq-full(ipset) | $(ts_re "$(dnsmasq --version |grep -v no-ipset |grep ipset)") |
| dnsmasq-full(nftset) | $(ts_re "$(dnsmasq --version |grep nftset)") |
| bash | $(ts_re "$(ipk_v "bash")") |
| curl | $(ts_re "$(ipk_v "curl")") |
| ca-bundle | $(ts_re "$(ipk_v "ca-bundle")") |
| ipset | $(ts_re "$(ipk_v "ipset")") |
| ip-full | $(ts_re "$(ipk_v "ip-full")") |
| ruby | $(ts_re "$(ipk_v "ruby")") |
| ruby-yaml | $(ts_re "$(ipk_v "ruby-yaml")") |
| ruby-psych | $(ts_re "$(ipk_v "ruby-psych")") |
| ruby-pstore | $(ts_re "$(ipk_v "ruby-pstore")") |
| ruby功能测试 | $(ruby -e "require 'yaml'; YAML.load('test: ok'); puts '正常'" 2>/dev/null || echo "异常") |
| kmod-tun(TUN模式) | $(ts_re "$(ipk_v "kmod-tun")") |
| luci-compat | $(ts_re "$(ipk_v "luci-compat")") |
| kmod-inet-diag | $(ts_re "$(ipk_v "kmod-inet-diag")") |
| unzip | $(ts_re "$(ipk_v "unzip")") |
EOF
if [ -n "$(command -v fw4)" ]; then
cat >> "$DEBUG_LOG" <<-EOF
kmod-nft-tproxy: $(ts_re "$(ipk_v kmod-nft-tproxy)")
| kmod-nft-tproxy | $(ts_re "$(ipk_v kmod-nft-tproxy)") |
EOF
else
cat >> "$DEBUG_LOG" <<-EOF
iptables-mod-tproxy: $(ts_re "$(ipk_v "iptables-mod-tproxy")")
kmod-ipt-tproxy: $(ts_re "$(ipk_v "kmod-ipt-tproxy")")
iptables-mod-extra: $(ts_re "$(ipk_v "iptables-mod-extra")")
kmod-ipt-extra: $(ts_re "$(ipk_v "kmod-ipt-extra")")
kmod-ipt-nat: $(ts_re "$(ipk_v "kmod-ipt-nat")")
| iptables-mod-tproxy | $(ts_re "$(ipk_v "iptables-mod-tproxy")") |
| kmod-ipt-tproxy | $(ts_re "$(ipk_v "kmod-ipt-tproxy")") |
| iptables-mod-extra | $(ts_re "$(ipk_v "iptables-mod-extra")") |
| kmod-ipt-extra | $(ts_re "$(ipk_v "kmod-ipt-extra")") |
| kmod-ipt-nat | $(ts_re "$(ipk_v "kmod-ipt-nat")") |
EOF
fi
cat >> "$DEBUG_LOG" <<-EOF
#内核模块加载状态:
### 内核模块加载状态
\`\`\`bash
# lsmod | grep -E 'tun|tproxy|inet_diag'
$(lsmod | grep -E 'tun|tproxy|inet_diag' 2>/dev/null || echo "无相关模块")
\`\`\`
EOF
#core
cat >> "$DEBUG_LOG" <<-EOF
#===================== 内核检查 =====================#
## 内核检查
| 项目 | 值 |
|------|----|
EOF
if pidof clash >/dev/null; then
cat >> "$DEBUG_LOG" <<-EOF
运行状态: 运行中
运行内核:$core_type
进程pid: $(pidof clash)
运行用户: $(ps |grep "/etc/openclash/clash" |grep -v grep |awk '{print $2}' 2>/dev/null)
| 运行状态 | 运行中 |
| 运行内核 | $core_type |
| 进程pid | $(pidof clash) |
| 运行用户 | $(ps |grep "/etc/openclash/clash" |grep -v grep |awk '{print $2}' 2>/dev/null) |
EOF
else
cat >> "$DEBUG_LOG" <<-EOF
运行状态: 未运行
| 运行状态 | 未运行 |
EOF
fi
if [ "$core_model" = "0" ]; then
core_model="未选择架构"
fi
cat >> "$DEBUG_LOG" <<-EOF
已选择的架构: $core_model
#下方无法显示内核版本号时请确认您的内核版本是否正确或者有无权限
EOF
cat >> "$DEBUG_LOG" <<-EOF
Meta内核版本: $core_meta_version
| 已选择的架构 | $core_model |
| Meta 内核版本 | $core_meta_version |
EOF
if [ ! -f "/etc/openclash/core/clash_meta" ]; then
cat >> "$DEBUG_LOG" <<-EOF
Meta内核文件: 不存在
| Meta 内核文件 | 不存在 |
EOF
else
cat >> "$DEBUG_LOG" <<-EOF
Meta内核文件: 存在
| Meta 内核文件 | 存在 |
EOF
fi
if [ ! -x "/etc/openclash/core/clash_meta" ]; then
cat >> "$DEBUG_LOG" <<-EOF
Meta内核运行权限: 否
| Meta 内核运行权限 | 否 |
EOF
else
cat >> "$DEBUG_LOG" <<-EOF
Meta内核运行权限: 正常
| Meta 内核运行权限 | 正常 |
EOF
fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== GEO 数据文件 =====================#
## GEO 数据文件
\`\`\`bash
# ls -lh /etc/openclash/Country.mmdb /etc/openclash/GeoIP.dat /etc/openclash/GeoSite.dat /etc/openclash/ASN.mmdb
$(ls -lh /etc/openclash/Country.mmdb /etc/openclash/GeoIP.dat /etc/openclash/GeoSite.dat /etc/openclash/ASN.mmdb 2>/dev/null)
\`\`\`
#===================== 模型、缓存文件状态 =====================#
## 模型、缓存文件状态
Model.bin: $(ls -lh /etc/openclash/Model.bin 2>/dev/null || echo "不存在")
cache.db: $(ls -lh /etc/openclash/cache.db 2>/dev/null || echo "不存在")
| 文件 | 状态 |
|------|------|
| Model.bin | $(ls -lh /etc/openclash/Model.bin 2>/dev/null || echo "不存在") |
| cache.db | $(ls -lh /etc/openclash/cache.db 2>/dev/null || echo "不存在") |
#===================== 冲突插件检测 =====================#
## 冲突插件检测
\`\`\`bash
# ps | grep -E 'passwall|ssr-plus|bypass|helloworld'
$(ps | grep -E 'passwall|ssr-plus|bypass|helloworld' | grep -v grep 2>/dev/null || echo "未检测到冲突插件")
\`\`\`
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== 插件设置 =====================#
## 插件设置
当前配置文件: $RAW_CONFIG_FILE
启动配置文件: $CONFIG_FILE
运行模式: $en_mode
默认代理模式: $proxy_mode
UDP流量转发(tproxy): $(ts_cf "$enable_udp_proxy")
自定义DNS: $(ts_cf "$enable_custom_dns")
IPV6代理: $(ts_cf "$ipv6_enable")
IPV6-DNS解析: $(ts_cf "$ipv6_dns")
禁用Dnsmasq缓存: $(ts_cf "$disable_masq_cache")
自定义规则: $(ts_cf "$enable_custom_clash_rules")
仅允许内网: $(ts_cf "$intranet_allowed")
仅代理命中规则流量: $(ts_cf "$enable_rule_proxy")
仅允许常用端口流量: $(ts_cf "$common_ports")
绕过中国大陆IP: $(ts_cf "$china_ip_route")
路由本机代理: $(ts_cf "$router_self_proxy")
TUN堆栈类型: ${stack_type:-system}
启动延迟: ${delay_start:-0}秒
日志大小: ${log_size:-1024}KB
旁路由兼容: $(ts_cf "$bypass_gateway_compatible")
禁用quic-go GSO: $(ts_cf "$disable_quic_go_gso")
小闪存模式: $(ts_cf "$small_flash_memory")
域名嗅探: $(ts_cf "$enable_meta_sniffer")
DNS代理: $(ts_cf "$enable_respect_rules")
绕过服务器地址: $(ts_cf "$skip_proxy_address")
禁用QUIC: $(ts_cf "$disable_udp_quic")
访问控制模式: $([ "$lan_ac_mode" = "1" ] && echo "White" || echo "Black")
IPv6模式: ${ipv6_mode:-0}
绕过IPv6区域: $(ts_cf "$china_ip6_route")
| 设置项 | 值 |
|--------|----|
| 当前配置文件 | $RAW_CONFIG_FILE |
| 启动配置文件 | $CONFIG_FILE |
| 运行模式 | $en_mode |
| 默认代理模式 | $proxy_mode |
| UDP流量转发 | $(ts_cf "$enable_udp_proxy") |
| 自定义DNS | $(ts_cf "$enable_custom_dns") |
| IPV6代理 | $(ts_cf "$ipv6_enable") |
| IPV6-DNS解析 | $(ts_cf "$ipv6_dns") |
| 禁用Dnsmasq缓存 | $(ts_cf "$disable_masq_cache") |
| 自定义规则 | $(ts_cf "$enable_custom_clash_rules") |
| 仅允许内网 | $(ts_cf "$intranet_allowed") |
| 仅代理命中规则流量 | $(ts_cf "$enable_rule_proxy") |
| 仅允许常用端口流量 | $(ts_cf "$common_ports") |
| 绕过中国大陆IP | $(ts_cf "$china_ip_route") |
| 路由本机代理 | $(ts_cf "$router_self_proxy") |
| TUN堆栈类型 | ${stack_type:-system} |
| 启动延迟 | ${delay_start:-0}秒 |
| 日志大小 | ${log_size:-1024}KB |
| 旁路由兼容 | $(ts_cf "$bypass_gateway_compatible") |
| 禁用quic-go GSO | $(ts_cf "$disable_quic_go_gso") |
| 小闪存模式 | $(ts_cf "$small_flash_memory") |
| 域名嗅探 | $(ts_cf "$enable_meta_sniffer") |
| DNS代理 | $(ts_cf "$enable_respect_rules") |
| 绕过服务器地址 | $(ts_cf "$skip_proxy_address") |
| 禁用QUIC | $(ts_cf "$disable_udp_quic") |
| 访问控制模式 | $([ "$lan_ac_mode" = "1" ] && echo "White" || echo "Black") |
| IPv6模式 | $(ipv6_mode_name "$ipv6_mode") |
| 绕过IPv6区域 | $(ts_cf "$china_ip6_route") |
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== Cron 定时任务 =====================#
## Cron 定时任务
\`\`\`bash
# crontab -l | grep -i openclash
$(crontab -l 2>/dev/null | grep -i openclash || echo "无 OpenClash 相关 cron 任务")
EOF
\`\`\`
cat >> "$DEBUG_LOG" <<-EOF
#===================== 覆写模块设置 =====================#
## 覆写模块设置
\`\`\`bash
# uci show openclash.@overwrite[0]
$(uci -q show openclash.@overwrite[0])
\`\`\`
EOF
if [ "$enable_custom_clash_rules" -eq 1 ]; then
cat >> "$DEBUG_LOG" <<-EOF
#===================== 自定义规则 一 =====================#
## 自定义规则 一 (优先匹配)
\`\`\`bash
# cat /etc/openclash/custom/openclash_custom_rules.list
EOF
cat /etc/openclash/custom/openclash_custom_rules.list >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#===================== 自定义规则 二 =====================#
## 自定义规则 二 (扩展匹配)
\`\`\`bash
# cat /etc/openclash/custom/openclash_custom_rules_2.list
EOF
cat /etc/openclash/custom/openclash_custom_rules_2.list >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== 配置文件 =====================#
## 配置文件
\`\`\`yaml
# ruby_read [config] (filtered: without proxies/proxy-providers)
EOF
if [ -f "$CONFIG_FILE" ]; then
ruby_read "$CONFIG_FILE" ".select {|x| 'proxies' != x and 'proxy-providers' != x }.to_yaml" 2>/dev/null >> "$DEBUG_LOG"
else
ruby_read "$RAW_CONFIG_FILE" ".select {|x| 'proxies' != x and 'proxy-providers' != x }.to_yaml" 2>/dev/null >> "$DEBUG_LOG"
fi
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
sed -i '/^ \{0,\}secret:/d' "$DEBUG_LOG" 2>/dev/null
#custom overwrite
cat >> "$DEBUG_LOG" <<-EOF
#===================== 自定义覆写设置 =====================#
## 自定义覆写设置
\`\`\`bash
# cat /etc/openclash/custom/openclash_custom_overwrite.sh
EOF
cat /etc/openclash/custom/openclash_custom_overwrite.sh >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
#firewall
cat >> "$DEBUG_LOG" <<-EOF
#===================== 自定义防火墙设置 =====================#
## 自定义防火墙设置
\`\`\`bash
# cat /etc/openclash/custom/openclash_custom_firewall_rules.sh
EOF
cat /etc/openclash/custom/openclash_custom_firewall_rules.sh >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== IPTABLES 防火墙设置 =====================#
## IPTABLES 防火墙设置
#IPv4 NAT chain
### IPv4 NAT chain
\`\`\`bash
# iptables-save -t nat
EOF
iptables-save -t nat >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#IPv4 Mangle chain
### IPv4 Mangle chain
\`\`\`bash
# iptables-save -t mangle
EOF
iptables-save -t mangle >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#IPv4 Filter chain
### IPv4 Filter chain
\`\`\`bash
# iptables-save -t filter
EOF
iptables-save -t filter >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#IPv6 NAT chain
### IPv6 NAT chain
\`\`\`bash
# ip6tables-save -t nat
EOF
ip6tables-save -t nat >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#IPv6 Mangle chain
### IPv6 Mangle chain
\`\`\`bash
# ip6tables-save -t mangle
EOF
ip6tables-save -t mangle >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#IPv6 Filter chain
### IPv6 Filter chain
\`\`\`bash
# ip6tables-save -t filter
EOF
ip6tables-save -t filter >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
if [ -n "$(command -v fw4)" ]; then
cat >> "$DEBUG_LOG" <<-EOF
#===================== NFTABLES 防火墙设置 =====================#
## NFTABLES 防火墙设置
\`\`\`bash
# nft list chain inet fw4 (all chains)
EOF
for nft in "input" "forward" "dstnat" "srcnat" "nat_output" "mangle_prerouting" "mangle_output"; do
nft list chain inet fw4 "$nft" >> "$DEBUG_LOG" 2>/dev/null
@@ -413,141 +497,221 @@ EOF
for nft in "openclash" "openclash_mangle" "openclash_mangle_output" "openclash_output" "openclash_post" "openclash_wan_input" "openclash_dns_hijack" "openclash_dns_redirect" "openclash_v6" "openclash_mangle_v6" "openclash_mangle_output_v6" "openclash_output_v6" "openclash_post_v6" "openclash_wan6_input"; do
nft list chain inet fw4 "$nft" >> "$DEBUG_LOG" 2>/dev/null
done >/dev/null 2>&1
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== IPSET状态 =====================#
## IPSET状态
\`\`\`bash
# ipset list -t
EOF
ipset list -t >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== 路由表状态 =====================#
## 路由表状态
EOF
echo "#IPv4" >> "$DEBUG_LOG"
echo "### IPv4" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#route -n" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# route -n" >> "$DEBUG_LOG"
route -n >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#ip route list" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# ip route list" >> "$DEBUG_LOG"
ip route list >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#ip route list table 354" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# ip route list table 354" >> "$DEBUG_LOG"
ip route list table 354 >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#ip rule show" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# ip rule show" >> "$DEBUG_LOG"
ip rule show >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#IPv6" >> "$DEBUG_LOG"
echo "### IPv6" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#route -A inet6" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# route -A inet6" >> "$DEBUG_LOG"
route -A inet6 >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#ip -6 route list" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# ip -6 route list" >> "$DEBUG_LOG"
ip -6 route list >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#ip -6 route list table 354" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# ip -6 route list table 354" >> "$DEBUG_LOG"
ip -6 route list table 354 >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
echo "#ip -6 rule show" >> "$DEBUG_LOG"
echo "\`\`\`bash" >> "$DEBUG_LOG"
echo "# ip -6 rule show" >> "$DEBUG_LOG"
ip -6 rule show >> "$DEBUG_LOG" 2>/dev/null
echo "\`\`\`" >> "$DEBUG_LOG"
if [ "$en_mode" != "fake-ip" ] && [ "$en_mode" != "redir-host" ]; then
cat >> "$DEBUG_LOG" <<-EOF
#===================== Tun设备状态 =====================#
## Tun设备状态
\`\`\`bash
# ip tuntap list
EOF
ip tuntap list >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== 端口占用状态 =====================#
## 端口占用状态
\`\`\`bash
# netstat -nlp | grep clash
EOF
netstat -nlp |grep clash >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#===================== 网络接口状态 =====================#
## 网络接口状态
\`\`\`bash
# ip link show && ip addr show | grep -E 'inet |utun'
EOF
ip link show >> "$DEBUG_LOG" 2>/dev/null
ip addr show | grep -E 'inet |utun' >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
cat >> "$DEBUG_LOG" <<-EOF
#===================== 测试本机DNS查询(www.baidu.com) =====================#
## 测试本机DNS查询(www.baidu.com)
\`\`\`bash
# nslookup www.baidu.com
EOF
nslookup www.baidu.com >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
#===================== 测试内核DNS查询(www.instagram.com) =====================#
## 测试内核DNS查询(www.instagram.com)
\`\`\`bash
# openclash_debug_dns.lua www.instagram.com
EOF
/usr/share/openclash/openclash_debug_dns.lua "www.instagram.com" >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
cat >> "$DEBUG_LOG" <<-EOF
Dnsmasq 当前默认 resolv 文件:$dnsmasq_default_resolvfile
## DNS 解析文件
### **Dnsmasq 当前默认 resolv 文件:** \`$dnsmasq_default_resolvfile\`
EOF
if [ -s "/tmp/resolv.conf.auto" ]; then
cat >> "$DEBUG_LOG" <<-EOF
#===================== /tmp/resolv.conf.auto =====================#
### /tmp/resolv.conf.auto
\`\`\`bash
# cat /tmp/resolv.conf.auto
EOF
cat /tmp/resolv.conf.auto >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
fi
if [ -s "/tmp/resolv.conf.d/resolv.conf.auto" ]; then
cat >> "$DEBUG_LOG" <<-EOF
#===================== /tmp/resolv.conf.d/resolv.conf.auto =====================#
### /tmp/resolv.conf.d/resolv.conf.auto
\`\`\`bash
# cat /tmp/resolv.conf.d/resolv.conf.auto
EOF
cat /tmp/resolv.conf.d/resolv.conf.auto >> "$DEBUG_LOG"
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== 测试本机网络连接(www.baidu.com) =====================#
## 测试本机网络连接(www.baidu.com)
\`\`\`bash
# curl -SsI -m 5 www.baidu.com
EOF
curl -SsI -m 5 www.baidu.com >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
LICENSE_URL="https://raw.githubusercontent.com/vernesong/OpenClash/refs/heads/master/LICENSE"
cat >> "$DEBUG_LOG" <<-EOF
#===================== 测试本机网络下载(raw.githubusercontent.com) =====================#
## 测试本机网络下载([raw.githubusercontent.com]($LICENSE_URL))
\`\`\`bash
# curl -SsIL -m 3 --retry 2 $LICENSE_URL
EOF
curl -SsIL -m 3 --retry 2 "$LICENSE_URL" >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
VERSION_URL="https://raw.githubusercontent.com/vernesong/OpenClash/refs/heads/master/LICENSE"
if pidof clash >/dev/null; then
curl -SsIL -m 3 --retry 2 "$VERSION_URL" >> "$DEBUG_LOG" 2>/dev/null
else
curl -SsIL -m 3 --retry 2 "$VERSION_URL" >> "$DEBUG_LOG" 2>/dev/null
fi
if pidof clash >/dev/null; then
cat >> "$DEBUG_LOG" <<-EOF
#===================== Mihomo API 健康检查 =====================#
## Mihomo API 健康检查
\`\`\`json
# curl -Ss -m 3 -H "Authorization: Bearer [password]" http://127.0.0.1:[cn_port]/version
EOF
curl -Ss -m 3 -H "Authorization: Bearer ${da_password}" http://127.0.0.1:${cn_port}/version >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
curl -Ss -m 3 http://127.0.0.1:${cn_port}/version >> "$DEBUG_LOG" 2>/dev/null
fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== 最近运行日志 (切换为Debug模式) =====================#
## 最近运行日志 (切换为Debug模式)
\`\`\`bash
# tail -n 100 /tmp/openclash.log
EOF
if pidof clash >/dev/null && [ "$log_level" != "debug" ]; then
@@ -556,9 +720,9 @@ if pidof clash >/dev/null && [ "$log_level" != "debug" ]; then
fi
tail -n 100 "/tmp/openclash.log" >> "$DEBUG_LOG" 2>/dev/null
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
#===================== 最近运行日志获取完成 =====================#
\`\`\`
EOF
if pidof clash >/dev/null && [ "$log_level" != "debug" ]; then
@@ -567,13 +731,14 @@ fi
cat >> "$DEBUG_LOG" <<-EOF
#===================== 活动连接信息 =====================#
## 活动连接信息
\`\`\`bash
# openclash_debug_getcon.lua
EOF
/usr/share/openclash/openclash_debug_getcon.lua
echo "" >> "$DEBUG_LOG"
cat >> "$DEBUG_LOG" <<-EOF
\`\`\`
EOF
@@ -9,6 +9,8 @@ CLASH="/etc/openclash/clash"
CFG_UPDATE_INT=0
SKIP_PROXY_ADDRESS=1
SKIP_PROXY_ADDRESS_INTERVAL=30
UPNP_INT=1
UPNP_INTERVAL=30
STREAM_AUTO_SELECT=0
FIREWALL_RELOAD=0
MAX_FIREWALL_RELOAD=3
@@ -51,12 +53,16 @@ begin
begin
provider_config = YAML.load_file(path, secret: provider['age-secret-key']) rescue nil
rescue Exception => e
YAML.LOG_WARN('Set Proxies Address Skip Failed,【' + path + ': ' + e.message+'】')
YAML.LOG_WARN('Set Proxies Address Skip: Failed【' + path + ': ' + e.message+'】')
continue
end
else
if file_is_age_encrypted
YAML.LOG_WARN('Set Proxies Address Skip Failed,【' + path + ': File is AGE encrypted but no secret key provided】')
if name == 'oixCloud'
YAML.LOG_TIP('Set Proxies Address Skip: Bypass【oixCloud】')
else
YAML.LOG_WARN('Set Proxies Address Skip: Failed【' + path + '】File is AGE encrypted but no secret key provided')
end
next
end
provider_config = YAML.load_file(path)
@@ -70,7 +76,7 @@ begin
rescue Psych::SyntaxError, ArgumentError
if not provider.key?('age-secret-key') or provider['age-secret-key'].to_s.empty?
if file_is_age_encrypted
YAML.LOG_WARN('Failed to parse config file with Lua helper【' + path + ': File is AGE encrypted, cannot parse with Lua】')
YAML.LOG_WARN('Failed to parse config file with Lua helper【' + path + '】File is AGE encrypted, cannot parse with Lua')
next
end
begin
@@ -159,7 +165,7 @@ begin
system(set_commands.join('; ')) if not set_commands.empty?
end
rescue Exception => e
YAML.LOG_ERROR('Set Proxies Address Skip Failed,【' + e.message + '】');
YAML.LOG_ERROR('Set Proxies Address Skip: Failed【' + e.message + '】');
end" 2>/dev/null >> $LOG_FILE
}
@@ -303,56 +309,61 @@ fi
fi
## UPNP
if [ -f "$upnp_lease_file" ]; then
#del
if [ -n "$FW4" ]; then
for i in `$(nft list chain inet fw4 openclash_upnp |grep "return")`
do
upnp_ip=$(echo "$i" |awk -F 'ip saddr ' '{print $2}' |awk '{print $1}')
upnp_dp=$(echo "$i" |awk -F 'sport ' '{print $2}' |awk '{print $1}')
upnp_type=$(echo "$i" |awk -F 'sport ' '{print $1}' |awk '{print $4}' |tr '[a-z]' '[A-Z]')
if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then
if [ -z "$(cat "$upnp_lease_file" |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
handle=$(nft -a list chain inet fw4 openclash_upnp |grep "$i" |awk -F '# handle ' '{print$2}')
nft delete rule inet fw4 openclash_upnp handle ${handle}
fi
fi
done >/dev/null 2>&1
else
for i in `$(iptables -t mangle -nL openclash_upnp |grep "RETURN")`
do
upnp_ip=$(echo "$i" |awk '{print $4}')
upnp_dp=$(echo "$i" |awk -F 'spt:' '{print $2}')
upnp_type=$(echo "$i" |awk '{print $2}' |tr '[a-z]' '[A-Z]')
if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then
if [ -z "$(cat "$upnp_lease_file" |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
iptables -t mangle -D openclash_upnp -p "$upnp_type" -s "$upnp_ip" --sport "$upnp_dp" -j RETURN 2>/dev/null
fi
fi
done >/dev/null 2>&1
fi
#add
if [ -s "$upnp_lease_file" ] && [ -n "$(iptables --line-numbers -t nat -xnvL openclash_upnp 2>/dev/null)"] || [ -n "$(nft list chain inet fw4 openclash_upnp 2>/dev/null)"]; then
cat "$upnp_lease_file" |while read -r line
do
if [ -n "$line" ]; then
upnp_ip=$(echo "$line" |awk -F ':' '{print $3}')
upnp_dp=$(echo "$line" |awk -F ':' '{print $4}')
upnp_type=$(echo "$line" |awk -F ':' '{print $1}' |tr '[A-Z]' '[a-z]')
if [ "$UPNP_INT" -eq 1 ] || [ "$(expr "$UPNP_INT" % "$UPNP_INTERVAL")" -eq 0 ]; then
if [ -f "$upnp_lease_file" ]; then
#del
if [ -n "$FW4" ]; then
for i in `$(nft list chain inet fw4 openclash_upnp |grep "return")`
do
upnp_ip=$(echo "$i" |awk -F 'ip saddr ' '{print $2}' |awk '{print $1}')
upnp_dp=$(echo "$i" |awk -F 'sport ' '{print $2}' |awk '{print $1}')
upnp_type=$(echo "$i" |awk -F 'sport ' '{print $1}' |awk '{print $4}' |tr '[a-z]' '[A-Z]')
if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then
if [ -n "$FW4" ]; then
if [ -z "$(nft list chain inet fw4 openclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
nft add rule inet fw4 openclash_upnp ip saddr { "$upnp_ip" } "$upnp_type" sport "$upnp_dp" counter return 2>/dev/null
fi
else
if [ -z "$(iptables -t mangle -nL openclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
iptables -t mangle -A openclash_upnp -p "$upnp_type" -s "$upnp_ip" --sport "$upnp_dp" -j RETURN 2>/dev/null
if [ -z "$(cat "$upnp_lease_file" |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
handle=$(nft -a list chain inet fw4 openclash_upnp |grep "$i" |awk -F '# handle ' '{print$2}')
nft delete rule inet fw4 openclash_upnp handle ${handle}
fi
fi
done >/dev/null 2>&1
else
for i in `$(iptables -t mangle -nL openclash_upnp |grep "RETURN")`
do
upnp_ip=$(echo "$i" |awk '{print $4}')
upnp_dp=$(echo "$i" |awk -F 'spt:' '{print $2}')
upnp_type=$(echo "$i" |awk '{print $2}' |tr '[a-z]' '[A-Z]')
if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then
if [ -z "$(cat "$upnp_lease_file" |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
iptables -t mangle -D openclash_upnp -p "$upnp_type" -s "$upnp_ip" --sport "$upnp_dp" -j RETURN 2>/dev/null
fi
fi
done >/dev/null 2>&1
fi
#add
if [ -s "$upnp_lease_file" ] && [ -n "$(iptables --line-numbers -t nat -xnvL openclash_upnp 2>/dev/null)"] || [ -n "$(nft list chain inet fw4 openclash_upnp 2>/dev/null)"]; then
cat "$upnp_lease_file" |while read -r line
do
if [ -n "$line" ]; then
upnp_ip=$(echo "$line" |awk -F ':' '{print $3}')
upnp_dp=$(echo "$line" |awk -F ':' '{print $4}')
upnp_type=$(echo "$line" |awk -F ':' '{print $1}' |tr '[A-Z]' '[a-z]')
if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then
if [ -n "$FW4" ]; then
if [ -z "$(nft list chain inet fw4 openclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
nft add rule inet fw4 openclash_upnp ip saddr { "$upnp_ip" } "$upnp_type" sport "$upnp_dp" counter return 2>/dev/null
fi
else
if [ -z "$(iptables -t mangle -nL openclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
iptables -t mangle -A openclash_upnp -p "$upnp_type" -s "$upnp_ip" --sport "$upnp_dp" -j RETURN 2>/dev/null
fi
fi
fi
fi
fi
done >/dev/null 2>&1
done >/dev/null 2>&1
fi
fi
let UPNP_INT++
else
let UPNP_INT++
fi
## Skip Proxies Address
@@ -86,6 +86,9 @@ external-controller-unix: mihomo.sock
# !!!注意: 从Windows namedpipe访问api接口不会验证secret, 如果开启请自行保证安全问题 !!!
external-controller-pipe: \\.\pipe\mihomo
# 为 external-controller 和 external-controller-tls 的监听socket设置routing-mark(仅支持linux)
external-controller-routing-mark: 0
# tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP
# 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问
@@ -174,6 +177,10 @@ tun:
#- 1000
# exclude-uid-range: # 排除路由的的用户范围
# - 1000:9999
# include-mac-address:
# - 00:11:22:33:44:55
# exclude-mac-address:
# - 00:11:22:33:44:55
# Android 用户和应用规则仅在 Android 下被支持
# 并且需要 auto-route
@@ -309,6 +316,7 @@ dns:
- https://mozilla.cloudflare-dns.com/dns-query#DNS&h3=true # 指定策略组和使用 HTTP/3
- dhcp://en0 # dns from dhcp
- quic://dns.adguard.com:784 # DNS over QUIC
# - ts://tailscale # 使用指定 Tailscale 出站的 DNS 配置查询
# - '8.8.8.8#RULES' # 效果同respect-rules,但仅对该服务器生效
# - '8.8.8.8#en0' # 兼容指定 DNS 出口网卡
@@ -333,18 +341,20 @@ dns:
# 配置 fallback 使用条件
# fallback-filter:
# geoip: true # 配置是否使用 geoip
# geoip-code: CN # 当 nameserver 域名的 IP 查询 geoip 库为 CN 时,不使用 fallback 中的 DNS 查询结果
# 配置强制 fallback,优先于 IP 判断,具体分类自行查看 geosite 库
# geosite:
# - gfw
# 如果不匹配 ipcidr 则使用 nameservers 中的结果
# ipcidr:
# geoip: true # 配置是否使用 geoip
# geoip-code: CN # 当 nameserver 解析出域名的 IP 查询 geoip 库为 CN 时, 使用 nameserver 中的 DNS 查询结果
# ipcidr: # 当 nameserver 解析出域名的 IP 匹配 ipcidr 时,使用 fallback 中的 DNS 查询结果
# - 240.0.0.0/4
# domain:
# - 0.0.0.0/32
# - 127.0.0.1/32
# - 100.64.0.0/10
# domain: # 匹配到这些域名,会直接使用 fallback 解析,不去使用 nameserver
# - '+.google.com'
# - '+.facebook.com'
# - '+.youtube.com'
# geosite: # 匹配到这些域名,会直接使用 fallback 解析,不去使用 nameserver(已废弃,请使用 nameserver-policy)
# - gfw
# fallback-lazy-query: false # 默认值为 false ,如果为 true 会先判断来自 nameserver 的结果是否满足 fallback-filter 后再发起查询
# 配置查询域名使用的 DNS 服务器
nameserver-policy:
@@ -392,16 +402,32 @@ proxies: # socks5
# ip-version: dual
# Snell
# Beware that there's currently no UDP support yet
- name: "snell"
type: snell
server: server
port: 44046
psk: yourpsk
# version: 2
# version: 4 # support 1/2/3/4/5
# udp: true # support UDP on version 3/4/5
# reuse: false # v4/5 only
# obfs-opts:
# mode: http # or tls
# host: bing.com
# mode: http # or tls/shadow-tls
- name: "snell-shadow-tls"
type: snell
server: server
port: 44046
psk: yourpsk
# version: 4 # support 1/2/3/4/5
# udp: true # support UDP on version 3/4/5
# reuse: false # v4/5 only
# client-fingerprint: chrome
obfs-opts:
mode: shadow-tls
host: bing.com
password: "shadow_tls_password"
version: 2 # support 1/2/3
alpn: ["h2","http/1.1"]
# Shadowsocks
# cipher支持:
@@ -509,6 +535,60 @@ proxies: # socks5
# headers:
# custom: value
- name: "gost-relay-hop"
type: gost-relay
# Dynamic mode: relay connects to the target address requested by the upper proxy.
# Use this proxy through dialer-proxy to carry ss/vmess/vless/trojan/etc.
server: relay.example.com
port: 443
udp: true
tls: true
# mux: true # relay+mtls when tls is also true
# sni: relay.example.com
# username: user
# password: pass
# client-fingerprint: chrome
# fingerprint: xxxx
# certificate: ./client.crt
# private-key: ./client.key
# skip-cert-verify: true
- name: "ss6-gost-relay"
type: ss
# This address is dialed from the remote GOST relay server side.
# If the remote SS listens on 127.0.0.1:12345 on the relay server, write it here.
server: 127.0.0.1
port: 12345
cipher: chacha20-ietf-poly1305
password: "password"
udp: true
# udp-over-tcp: true # use this instead if your SS server expects UoT over TCP
dialer-proxy: gost-relay-hop
# - name: "gost-relay-forward-hop"
# type: gost-relay
# # Forward mode: relay server chooses its configured forwarding target.
# server: relay.example.com
# port: 443
# udp: true
# forward: true
# tls: true
# # mux: true
# # sni: relay.example.com
# # username: user
# # password: pass
#
# - name: "ss6-gost-relay-forward"
# type: ss
# # In forward mode this address is only used to ask dialer-proxy for a stream.
# # The GOST relay server forwards the stream to its configured target.
# server: relay.example.com
# port: 443
# cipher: chacha20-ietf-poly1305
# password: "password"
# udp: true
# dialer-proxy: gost-relay-forward-hop
- name: "ss-restls-tls13"
type: ss
server: [YOUR_SERVER_IP]
@@ -673,6 +753,9 @@ proxies: # socks5
grpc-service-name: "example"
# grpc-user-agent: "grpc-go/1.36.0"
# ping-interval: 0 # 默认关闭,单位为秒
# max-connections: 1 # Maximum connections. Conflict with max-streams.
# min-streams: 0 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams.
# max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams.
# ip-version: ipv4
# vless
@@ -764,6 +847,9 @@ proxies: # socks5
grpc-service-name: "grpc"
# grpc-user-agent: "grpc-go/1.36.0"
# ping-interval: 0 # 默认关闭,单位为秒
# max-connections: 1 # Maximum connections. Conflict with max-streams.
# min-streams: 0 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams.
# max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams.
reality-opts:
public-key: CrrQSjAG_YkHLwvM2M-7XkKJilgL5upBKCp0od0tLhE
@@ -800,8 +886,7 @@ proxies: # socks5
udp: true
tls: true
network: xhttp
alpn:
- h2
alpn: [h2] # 默认仅支持h2,如果开启h3模式需要设置alpn: [h3],如果开启http1.1模式需要设置alpn: [http/1.1]
# ech-opts: ...
# reality-opts: ...
# skip-cert-verify: false
@@ -819,32 +904,46 @@ proxies: # socks5
# X-Forwarded-For: ""
# no-grpc-header: false
# x-padding-bytes: "100-1000"
# x-padding-obfs-mode: false
# x-padding-key: x_padding
# x-padding-header: Referer
# x-padding-placement: queryInHeader # Available: queryInHeader, cookie, header, query
# x-padding-method: repeat-x # Available: repeat-x, tokenish
# uplink-http-method: POST # Available: POST, PUT, PATCH, DELETE
# session-placement: path # Available: path, query, cookie, header
# session-key: ""
# seq-placement: path # Available: path, query, cookie, header
# seq-key: ""
# uplink-data-placement: body # Available: body, cookie, header
# uplink-data-key: ""
# uplink-chunk-size: 0 # only applicable when uplink-data-placement is not body
# sc-max-each-post-bytes: 1000000
# sc-min-posts-interval-ms: 30
# reuse-settings: # aka XMUX
# max-connections: "16-32"
# max-concurrency: "0"
# max-concurrency: "16-32"
# max-connections: "0"
# c-max-reuse-times: "0"
# h-max-request-times: "600-900"
# h-max-reusable-secs: "1800-3000"
# h-keep-alive-period: 0
# download-settings:
# ## xhttp part
# path: "/"
# host: xxx.com
# headers:
# X-Forwarded-For: ""
# no-grpc-header: false
# x-padding-bytes: "100-1000"
# reuse-settings: # aka XMUX
# max-connections: "16-32"
# max-concurrency: "0"
# max-concurrency: "16-32"
# max-connections: "0"
# c-max-reuse-times: "0"
# h-max-request-times: "600-900"
# h-max-reusable-secs: "1800-3000"
# h-keep-alive-period: 0
# ## proxy part
# server: server
# port: 443
# tls: true
# alpn:
# - h2
# alpn: ...
# ech-opts: ...
# reality-opts: ...
# skip-cert-verify: false
@@ -899,6 +998,9 @@ proxies: # socks5
grpc-service-name: "example"
# grpc-user-agent: "grpc-go/1.36.0"
# ping-interval: 0 # 默认关闭,单位为秒
# max-connections: 1 # Maximum connections. Conflict with max-streams.
# min-streams: 0 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams.
# max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams.
- name: trojan-ws
server: server
@@ -970,13 +1072,16 @@ proxies: # socks5
server: server.com
port: 443
# ports: 1000,2000-3000,5000 # port 不可省略
# hop-interval: 15
# hop-interval: 15 # 支持填写"15-30"会每次随机选取其中一个值作为切换间隔,仅支持写一个范围(即不允许出现逗号)
# up 和 down 均不写或为 0 则使用 BBR 流控
# up: "30 Mbps" # 若不写单位,默认为 Mbps
# down: "200 Mbps" # 若不写单位,默认为 Mbps
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
password: yourpassword
# obfs: salamander # 默认为空,如果填写则开启 obfs,目前仅支持 salamander
# obfs: salamander # 默认为空,如果填写则开启 obfs,目前支持 salamander 和 gecko
# obfs-password: yourpassword
# obfs-min-packet-size: 512 # 最小线上数据包大小(字节)。仅限 Gecko。
# obfs-max-packet-size: 1200 # 最大线上数据包大小(字节)。仅限 Gecko。
# sni: server.com
# ech-opts:
# enable: true # 必须手动开启
@@ -990,6 +1095,18 @@ proxies: # socks5
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
# alpn:
# - h3
# realm-opts:
# enable: true # 必须手动开启
# server-url: https://realm.hy2.io
# token: public
# realm-id: my-cabin-1f3a8c2e9b
# stun-servers:
# - stun.nextcloud.com:3478
# - stun.sip.us:3478
# - global.stun.twilio.com:3478
# # 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, fingerprint, certificate, private-key, alpn)
# # skip-cert-verify: false
# # ......
###quic-go特殊配置项,不要随意修改除非你知道你在干什么###
# initial-stream-receive-window: 8388608
# max-stream-receive-window: 8388608
@@ -1051,6 +1168,73 @@ proxies: # socks5
# j3: <t><b 0xf6ab><c><r 10> # AmneziaWG v1.5 only (removed in v2)
# itime: 60 # AmneziaWG v1.5 only (removed in v2)
# tailscale
- name: "tailscale"
type: tailscale
# hostname: mihomo # Tailscale 设备名,默认由 tsnet 处理
# auth-key: tskey-auth-xxxx # 可选;不填写时首次启动会输出交互式登录 URL
# control-url: https://controlplane.tailscale.com # 可选;自定义 Headscale/Tailscale control server
# state-dir: ./tailscale # tsnet 状态目录,默认 tailscale
# ephemeral: false # 是否作为 ephemeral node 登录,默认 false
udp: true # 是否启用 UDP,默认 false
# accept-routes: true # 是否接受 Tailnet 中发布的 subnet routes
# exit-node: 100.64.0.1 # 使用指定 exit node,可填写节点 IP;也支持 auto:any
# exit-node-allow-lan-access: true # 使用 exit node 时是否允许访问本地 LAN
# 当目标不在 Tailscale 路由内时,连接会直接报错,不会回退到直连;
# 访问公网需要配置可用的 exit-node,或接受覆盖目标网段的 subnet routes。
# 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出 Tailscale 控制面和 DERP/STUN 等连接
# dialer-proxy: "ss1"
# interface-name: "WLAN" # 指定出站网卡
# routing-mark: 6666 # Linux 下配置 fwmark
# ip-version: ipv4-prefer # 可选:dual/ipv4/ipv6/ipv4-prefer/ipv6-prefer
# openvpn
- name: "openvpn"
type: openvpn
server: vpn.example.com
port: 1194
proto: udp # udp/tcp,默认 udp
# dev: tun # 目前仅支持 tun,默认 tun
# cipher: AES-128-GCM # 支持 AES-128-GCM / AES-192-GCM / AES-256-GCM / AES-128-CBC / AES-192-CBC / AES-256-CBC / CHACHA20-POLY1305,默认 AES-128-GCM;AES-CBC 会按 AES-128-CBC 处理
# auth: SHA256 # 支持 MD5 / SHA1 / SHA256 / SHA384 / SHA512,默认 SHA256;AEAD cipher 会忽略 auth
# comp-lzo: "no" # 可选值:"yes", "no", "adaptive"
# username / password: auth-user-pass 模式(与下方 cert+key 二选一,不能都不填)
# username: "user"
# password: "pass"
# 从 .ovpn 中复制 <ca></ca> 内的内容,不需要保留 <ca> 标签
ca: |
-----BEGIN CERTIFICATE-----
MIIB...example
-----END CERTIFICATE-----
# 从 .ovpn 中复制 <cert></cert> 内的内容(auth-user-pass 时可省略 cert / key)
cert: |
-----BEGIN CERTIFICATE-----
MIIB...example
-----END CERTIFICATE-----
# 从 .ovpn 中复制 <key></key> 内的内容
key: |
-----BEGIN PRIVATE KEY-----
MIIE...example
-----END PRIVATE KEY-----
# 从 .ovpn 中复制 <tls-crypt></tls-crypt> 内的内容,不需要保留 <tls-crypt> 标签;没有 tls-crypt 的配置可省略
# tls-crypt: |
# -----BEGIN OpenVPN Static key V1-----
# 00000000000000000000000000000000
# ...
# -----END OpenVPN Static key V1-----
# peer-info: # 透传给服务端的 peer-info 键值对,追加在内置 IV_VER/IV_PROTO/IV_CIPHERS 之后;用于服务端基于 peer-info 做准入决策
# IV_HWADDR: "52:54:00:ff:72:87"
# UV_DEVICE_ID: "laptop-001"
# ping: 10 # 默认值为 0
# ping-restart: 60 # 默认值为 0
# handshake-timeout: 30 # 单位为秒;配置后握手时不受外层连接超时影响;默认值为 0,表示仅使用外层连接超时
# mtu: 1500
udp: true
# 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接
# dialer-proxy: "ss1"
# remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false
# dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在 remote-dns-resolve 为 true 时生效
# masque
- name: "masque"
type: masque
@@ -1067,6 +1251,41 @@ proxies: # socks5
# remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false
# dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在 remote-dns-resolve 为 true 时生效
# congestion-controller: bbr # 默认不开启
# handshake-timeout: 30 # 单位为秒;配置后握手时不受外层连接超时影响;默认值为 0,表示仅使用外层连接超时
# masque-h3-l4proxy
- name: "masque-h3-l4proxy"
type: masque
server: 162.159.198.1
port: 443
private-key: MHcCAQEEILI1eOtnbEIh89Fj4yNDuFR6UjayCKI3NdLl3DhetimWoAoGCCqGSM49AwEHoUQDQgAEgyXrE8v+hHsHy3ewSb3WcRjYgCrM9T9hiE0Uv6k2DZ1+4kefrDT9v1Q/8wdRigTf6t6gGNUV8W+IUMdrfUt+9g==
public-key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIaU7MToJm9NKp8YfGxR6r+/h4mcG7SxI8tsW8OR1A5tv/zCzVbCRRh2t87/kxnP6lAy0lkr7qYwu+ox+k3dr6w==
udp: false # 目前 l4proxy 模式不支持 udp
network: h3-l4proxy
# 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接
# dialer-proxy: "ss1"
# remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false
# dns: [ tls://1.1.1.1, tls://1.0.0.1 ] # 仅在 remote-dns-resolve 为 true 时生效
# congestion-controller: bbr # 默认不开启
# handshake-timeout: 30 # 单位为秒;配置后握手时不受外层连接超时影响;默认值为 0,表示仅使用外层连接超时
# masque-h2
- name: "masque-h2"
type: masque
server: 162.159.198.2
port: 443
private-key: MHcCAQEEILI1eOtnbEIh89Fj4yNDuFR6UjayCKI3NdLl3DhetimWoAoGCCqGSM49AwEHoUQDQgAEgyXrE8v+hHsHy3ewSb3WcRjYgCrM9T9hiE0Uv6k2DZ1+4kefrDT9v1Q/8wdRigTf6t6gGNUV8W+IUMdrfUt+9g==
public-key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIaU7MToJm9NKp8YfGxR6r+/h4mcG7SxI8tsW8OR1A5tv/zCzVbCRRh2t87/kxnP6lAy0lkr7qYwu+ox+k3dr6w==
ip: 172.16.0.2
ipv6: 2606:4700:110:84c0:163a:4914:a0ad:3342
mtu: 1280
udp: true
network: h2
# 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接
# dialer-proxy: "ss1"
# remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false
# dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在 remote-dns-resolve 为 true 时生效
# handshake-timeout: 30 # 单位为秒;配置后握手时不受外层连接超时影响;默认值为 0,表示仅使用外层连接超时
# tuic
- name: tuic
@@ -1087,6 +1306,7 @@ proxies: # socks5
udp-relay-mode: native # Available: "native", "quic". Default: "native"
# congestion-controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic"
# cwnd: 10 # default: 32
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
# max-udp-relay-packet-size: 1500
# fast-open: true
# skip-cert-verify: true
@@ -1155,7 +1375,7 @@ proxies: # socks5
server: server_ip/domain # 1.2.3.4 or domain
port: 443
key: "<client_key>" # 如果你使用sudoku生成的ED25519密钥对,请填写密钥对中的私钥,否则填入和服务端相同的uuid
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;且 enable-pure-downlink=false 时不可用)
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;none 不提供 AEAD 保护)
padding-min: 2 # 最小填充率(0-100)
padding-max: 7 # 最大填充率(0-100,必须 >= padding-min)
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy、up_ascii_down_entropy、up_entropy_down_ascii
@@ -1169,7 +1389,7 @@ proxies: # socks5
# host: "" # 可选:覆盖 Host/SNI(支持 example.com 或 example.com:443);仅在 mode 为 stream/poll/auto/ws 时生效
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws
# multiplex: "off" # 可选字符串:off(默认)、auto(复用底层 HTTP 连接,减少建链 RTT)、on(Sudoku mux 单隧道多目标;仅在 mode=stream/poll/auto 生效;ws 强制 off)
enable-pure-downlink: false # 可选:false=带宽优化下行(更快,要求 aead-method != none);true=纯 Sudoku 下行
enable-pure-downlink: false # 可选:false=带宽优化下行;true=纯 Sudoku 下行
# anytls
- name: anytls
@@ -1202,30 +1422,30 @@ proxies: # socks5
# alpn:
# - h2
# skip-cert-verify: true
### quic options
# quic: true # 默认为false
# congestion-controller: bbr
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
### reuse options
# max-connections: 8 # Maximum connections. Conflict with max-streams.
# min-streams: 5 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams.
# max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams.
# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理
- name: "dns-out"
type: dns
- name: "rematch"
type: rematch
target-rematch-name: "rematch1" # 如果填写则覆盖原始 metadata 中的 rematch-name(可用REMATCH-NAME规则匹配)
target-sub-rule: "sub-rule1" # 如果填写则接下来会直接用指定的 sub-rule 匹配,如果名字不存在或为空会回退到主rules
# 配置指定 interface-name 和 fwmark 的 DIRECT
- name: en1-direct
type: direct
interface-name: en1
routing-mark: 6667
proxy-groups:
# 代理链,目前 relay 可以支持 udp 的只有 vmess/vless/trojan/ss/ssr/tuic
# wireguard 目前不支持在 relay 中使用,请使用 proxy 中的 dialer-proxy 配置项
# Traffic: mihomo <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet
- name: "relay"
type: relay
proxies:
- http
- vmess
- ss1
- ss2
# url-test 将按照 url 测试结果使用延迟最低节点
- name: "auto"
type: url-test
@@ -1269,6 +1489,7 @@ proxy-groups:
- ss2
- vmess1
- auto
# default-selected: ss1 # 默认选择的节点(该项为空或者设置的节点名不存在时,默认选择组中第一个节点)
- name: UseProvider
type: select
@@ -1278,6 +1499,7 @@ proxy-groups:
proxies:
- Proxy
- DIRECT
# empty-fallback: COMPATIBLE # 设置当组为空时的回退proxy(这里不支持填写代理组,只支持填写proxy名称)
# Mihomo 格式的节点或支持 *ray 的分享格式
proxy-providers:
@@ -1288,6 +1510,22 @@ proxy-providers:
path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到其他位置,请通过设置 SAFE_PATHS 环境变量指定额外的安全路径。该环境变量的语法同本操作系统的PATH环境变量解析规则(即Windows下以分号分割,其他系统下以冒号分割)
proxy: DIRECT
# size-limit: 10240 # 限制下载文件最大为10kb,默认为0即不限制文件大小
# #
# # 如果设置会age-secret-key尝试通过此secret解密age armor格式加密的配置文件
# #
# # 注意:
# # 对于加密内容,目前仅支持 age-encryption.org/v1 的 official ASCII "armor" format
# # 对于key格式,目前仅支持 age-encryption.org/v1 的 x25519 recipient type 和 The mlkem768-x25519 hybrid post-quantum recipient type
# # 实用工具:
# # 您可以通过 "mihomo age keygen" 生成符合要求的 x25519 key
# # 您可以通过 "mihomo age keygen-pq" 生成符合要求的 mlkem768-x25519 key
# # 您可以通过 "mihomo age convert <secret_key>" 从 age-secret-key 导出 age-public-key
# # 您可以通过 "mihomo age decrypt <secret_key> <source_file> <target_file>" 将已加密文件解密,<source_file> 为 - 时会从标准输入读取,<target_file> 为 - 时会往标准输出写入
# # 您可以通过 "mihomo age encrypt <public_key> <source_file> <target_file>" 将未加密文件加密,<source_file> 为 - 时会从标准输入读取,<target_file> 为 - 时会往标准输出写入
# # 参考实现:
# # https://github.com/FiloSottile/awesome-age#implementations
# #
# age-secret-key: AGE-SECRET-KEY-1ZTQLLN0A4U3ZTT3DCZKYN0CGZEZQLWX2DFTXUWMT4ZHR0N2UG6LSW9NT0N
header:
User-Agent:
- "Clash/v1.18.0"
@@ -1296,6 +1534,8 @@ proxy-providers:
# - 'application/vnd.github.v3.raw'
# Authorization:
# - 'token 1231231'
# X-Age-Public-Key:
# - 'age1xh86kh9v23vattr58yedspm3f57sxvnswu9krr6ns438amekx5gsd09uma'
health-check:
enable: true
interval: 600
@@ -1370,6 +1610,7 @@ rule-providers:
format: mrs
behavior: domain
path: /path/to/save/file.mrs
# path-in-bundle: "geo/geosite/cn.mrs" # 当设置该选项时,如果本地文件不存在,会优先从 Home Dir的 BundleMRS.7z 中解压该文件,此项的值用于指定在 BundleMRS.7z 中的路径
rule4:
type: inline
behavior: domain # classical / ipcidr
@@ -1421,6 +1662,7 @@ listeners:
type: socks
port: 10808 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
#listen: 0.0.0.0 # 默认监听 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理
# udp: false # 默认 true
@@ -1445,6 +1687,7 @@ listeners:
type: http
port: 10809 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
# users: # 如果不填写users项,则遵从全局authentication设置,如果填写会忽略全局设置, 如想跳过该入站的验证可填写 users: []
@@ -1468,6 +1711,7 @@ listeners:
type: mixed # HTTP(S) 和 SOCKS 代理混合
port: 10810 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
# udp: false # 默认 true
@@ -1507,10 +1751,14 @@ listeners:
type: shadowsocks
port: 10813 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
password: vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg=
cipher: 2022-blake3-aes-256-gcm
# simple-obfs:
# enable: false # 设置为true时开启
# mode: http # Available: http, tls
# shadow-tls:
# enable: false # 设置为true时开启
# version: 3 # 支持v1/v2/v3
@@ -1547,10 +1795,34 @@ listeners:
# streambuf: 2097152 # per stream receive buffer in bytes, smux v2+
# keepalive: 10 # seconds between heartbeats
- name: snell-in-1
type: snell
port: 10815 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
psk: your-password
version: 4 # 仅支持 4/5
udp: true # UDP over TCP tunnel,默认 true
# obfs-opts:
# mode: http # 可选:http / tls
# host: bing.com
# shadow-tls:
# enable: false # 设置为true时开启
# version: 3 # 支持v1/v2/v3
# password: password # v2设置项
# users: # v3设置项
# - name: 1
# password: password
# handshake:
# dest: test.com:443
# rule: sub-rule-name1
# proxy: proxy
- name: vmess-in-1
type: vmess
port: 10814 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
users:
@@ -1595,6 +1867,7 @@ listeners:
type: tuic
port: 10815 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
# token: # tuicV4 填写(可以同时填写 users)
@@ -1615,6 +1888,7 @@ listeners:
# dC5jb20AAA==
# -----END ECH KEYS-----
# congestion-controller: bbr
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
# max-idle-time: 15000
# authentication-timeout: 1000
# alpn:
@@ -1625,6 +1899,7 @@ listeners:
type: tunnel
port: 10816 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
network: [tcp, udp]
@@ -1634,6 +1909,7 @@ listeners:
type: vless
port: 10817 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
users:
@@ -1647,7 +1923,25 @@ listeners:
# host: ""
# mode: auto # Available: "stream-one", "stream-up" or "packet-up"
# no-sse-header: false
# x-padding-bytes: "100-1000"
# x-padding-obfs-mode: false
# x-padding-key: x_padding
# x-padding-header: Referer
# x-padding-placement: queryInHeader # Available: queryInHeader, cookie, header, query
# x-padding-method: repeat-x # Available: repeat-x, tokenish
# uplink-http-method: POST # Available: POST, PUT, PATCH, DELETE
# session-placement: path # Available: path, query, cookie, header
# session-key: ""
# session-table: "" # Available: "", "uuid", "ALPHABET", "Alphabet", "BASE36", "Base62", "HEX", "alphabet", "base36", "hex", "number"
# session-length: "16-32" # 起始值不可为 0,总的 id 空间必须大于 21 亿,仅当session-table不为空或uuid时生效
# seq-placement: path # Available: path, query, cookie, header
# seq-key: ""
# uplink-data-placement: body # Available: body, cookie, header
# uplink-data-key: ""
# uplink-chunk-size: 0 # only applicable when uplink-data-placement is not body
# sc-max-buffered-posts: 30
# sc-stream-up-server-secs: "20-80"
# sc-max-each-post-bytes: 1000000
# -------------------------
# vless encryption服务端配置:
# (原生外观 / 只 XOR 公钥 / 全随机数。1-RTT 每次下发随机 300 到 600 秒的 ticket 以便 0-RTT 复用 / 只允许 1-RTT)
@@ -1692,12 +1986,14 @@ listeners:
after-bytes: 0 # 传输指定字节后开始限速
bytes-per-sec: 0 # 基准速率(字节/秒)
burst-bytes-per-sec: 0 # 突发速率(字节/秒),大于 bytesPerSec 时生效
### 注意,对于vless listener, 至少需要填写 “certificate和private-key” 或 “reality-config” 或 “decryption” 的其中一项 ###
### 注意,对于vless listener, 如果 "allow-insecure" 不为 true, 至少需要填写 “certificate和private-key” 或 “reality-config” 或 “decryption” 的其中一项 ###
# allow-insecure: false # 是否允许不开启tls加密(注意:仅用于有 nginx, caddy 前置的情况)
- name: anytls-in-1
type: anytls
port: 10818 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
users:
username1: password1
username2: password2
@@ -1714,32 +2010,38 @@ listeners:
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
# dC5jb20AAA==
# -----END ECH KEYS-----
### 注意,anytls listener, 如果 "allow-insecure" 不为 true, 必须填写 “certificate和private-key” ###
# allow-insecure: false # 是否允许不开启tls加密(注意:仅用于有 nginx, caddy 前置的情况)
# padding-scheme: "" # https://github.com/anytls/anytls-go/blob/main/docs/protocol.md#cmdupdatepaddingscheme
- name: mieru-in-1
type: mieru
port: 10818 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
transport: TCP # 支持 TCP 或者 UDP
users:
username1: password1
username2: password2
# 一个 base64 字符串用于微调网络行为
# traffic-pattern: ""
# 如果开启,且客户端不发送用户提示,代理服务器将拒绝连接
# user-hint-is-mandatory: false
- name: sudoku-in-1
type: sudoku
port: 8443 # 仅支持单端口
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
key: "<server_key>" # 如果你使用sudoku生成的ED25519密钥对,此处是密钥对中的公钥,当然,你也可以仅仅使用任意uuid充当key
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;且 enable-pure-downlink=false 时不可用)
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;none 不提供 AEAD 保护)
padding-min: 1 # 最小填充率(0-100)
padding-max: 15 # 最大填充率(0-100,必须 >= padding-min)
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy、up_ascii_down_entropy、up_entropy_down_ascii
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合;只对 entropy 方向生效
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于多表轮换;非空时覆盖 custom-table
handshake-timeout: 5 # 可选(秒)
enable-pure-downlink: false # 可选:false=带宽优化下行(更快,要求 aead-method != none);true=纯 Sudoku 下行
enable-pure-downlink: false # 可选:false=带宽优化下行;true=纯 Sudoku 下行
# 推荐:使用 httpmask 对象统一管理 HTTPMask 相关字段:
httpmask:
disable: false # true 禁用所有 HTTP 伪装/隧道
@@ -1754,6 +2056,7 @@ listeners:
type: trojan
port: 10819 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
users:
@@ -1796,12 +2099,14 @@ listeners:
# enabled: false
# method: aes-128-gcm # aes-128-gcm/aes-256-gcm/chacha20-ietf-poly1305
# password: "example"
### 注意,对于trojan listener, 至少需要填写 “certificate和private-key” 或 “reality-config” 或 “ss-option” 的其中一项 ###
### 注意,对于trojan listener, 如果 "allow-insecure" 不为 true, 至少需要填写 “certificate和private-key” 或 “reality-config” 或 “ss-option” 的其中一项 ###
# allow-insecure: false # 是否允许不开启tls加密(注意:仅用于有 nginx, caddy 前置的情况)
- name: hysteria2-in-1
type: hysteria2
port: 10820 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
users:
@@ -1822,8 +2127,11 @@ listeners:
## up 和 down 均不写或为 0 则使用 BBR 流控
# up: "30 Mbps" # 若不写单位,默认为 Mbps
# down: "200 Mbps" # 若不写单位,默认为 Mbps
# obfs: salamander # 默认为空,如果填写则开启 obfs,目前仅支持 salamander
# obfs: salamander # 默认为空,如果填写则开启 obfs,目前支持 salamander 和 gecko
# obfs-password: yourpassword
# obfs-min-packet-size: 512 # 最小线上数据包大小(字节)。仅限 Gecko。
# obfs-max-packet-size: 1200 # 最大线上数据包大小(字节)。仅限 Gecko。
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
# max-idle-time: 15000
# alpn:
# - h3
@@ -1832,11 +2140,51 @@ listeners:
# masquerade: file:///var/www # 作为文件服务器
# masquerade: http://127.0.0.1:8080 #作为反向代理
# masquerade: https://127.0.0.1:8080 #作为反向代理
# realm-opts:
# enable: true # 必须手动开启
# server-url: https://realm.hy2.io
# token: public
# realm-id: my-cabin-1f3a8c2e9b
# stun-servers:
# - stun.nextcloud.com:3478
# - stun.sip.us:3478
# - global.stun.twilio.com:3478
# # proxy: DIRECT # 设置server-url通过哪个代理进行连接
# # 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, fingerprint, certificate, private-key, alpn)
# # skip-cert-verify: false
# # ......
# 注意,这是用于自建hysteria2入站和出站中realm-opts中server-url的HTTP/HTTPS服务器,请勿混淆
- name: hysteria2-realm-in-1
type: hysteria2-realm
port: 10820 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
token: public # hysteria2入站和出站通过 `Authorization: Bearer <token>` 出示的 Bearer 令牌。
max-realms: 65536 # maximum total realms (0 = unlimited)
max-realms-per-ip: 4 # maximum realms per client IP (0 = unlimited)
trusted-proxy-header: "" # header to read real client IP from (e.g. X-Forwarded-For)
realm-name-pattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$" # regex realm names must match
# # 下面内容如果配置, realm 将通过 TLS 提供 HTTPS 服务;否则提供明文 HTTP
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
# ech-key: |
# -----BEGIN ECH KEYS-----
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
# dC5jb20AAA==
# -----END ECH KEYS-----
# alpn: ["h2", "http/1.1"]
- name: trusttunnel-in-1
type: trusttunnel
port: 10821 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
listen: 0.0.0.0
# routing-mark: 0 # 为监听socket设置routing-mark(仅支持linux)
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
users:
@@ -1846,6 +2194,7 @@ listeners:
private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
network: ["tcp", "udp"] # http2+http3
congestion-controller: bbr
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
@@ -1888,6 +2237,10 @@ listeners:
# - 1000
# exclude-uid-range: # 排除路由的的用户范围
# - 1000:99999
# include-mac-address:
# - 00:11:22:33:44:55
# exclude-mac-address:
# - 00:11:22:33:44:55
# Android 用户和应用规则仅在 Android 下被支持
# 并且需要 auto-route
@@ -1917,6 +2270,7 @@ listeners:
# certificate: ./server.crt
# private-key: ./server.key
# congestion-controller: bbr
# bbr-profile: "" # Available: "standard", "conservative", "aggressive". Default: "standard"
# max-idle-time: 15000
# authentication-timeout: 1000
# alpn:
@@ -1,32 +0,0 @@
.CodeMirror-dialog {
position: absolute;
left: 0; right: 0;
background: inherit;
z-index: 15;
padding: .1em .8em;
overflow: hidden;
color: inherit;
}
.CodeMirror-dialog-top {
border-bottom: 1px solid #eee;
top: 0;
}
.CodeMirror-dialog-bottom {
border-top: 1px solid #eee;
bottom: 0;
}
.CodeMirror-dialog input {
border: none;
outline: none;
background: transparent;
width: 20em;
color: inherit;
font-family: monospace;
}
.CodeMirror-dialog button {
font-size: 70%;
}
@@ -1,163 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Open simple dialogs on top of an editor. Relies on dialog.css.
(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) {
function dialogDiv(cm, template, bottom) {
var wrap = cm.getWrapperElement();
var dialog;
dialog = wrap.appendChild(document.createElement("div"));
if (bottom)
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
else
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
if (typeof template == "string") {
dialog.innerHTML = template;
} else { // Assuming it's a detached DOM element.
dialog.appendChild(template);
}
CodeMirror.addClass(wrap, 'dialog-opened');
return dialog;
}
function closeNotification(cm, newVal) {
if (cm.state.currentNotificationClose)
cm.state.currentNotificationClose();
cm.state.currentNotificationClose = newVal;
}
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
if (!options) options = {};
closeNotification(this, null);
var dialog = dialogDiv(this, template, options.bottom);
var closed = false, me = this;
function close(newVal) {
if (typeof newVal == 'string') {
inp.value = newVal;
} else {
if (closed) return;
closed = true;
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
dialog.parentNode.removeChild(dialog);
me.focus();
if (options.onClose) options.onClose(dialog);
}
}
var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) {
inp.focus();
if (options.value) {
inp.value = options.value;
if (options.selectValueOnOpen !== false) {
inp.select();
}
}
if (options.onInput)
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
if (options.onKeyUp)
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
CodeMirror.on(inp, "keydown", function(e) {
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
inp.blur();
CodeMirror.e_stop(e);
close();
}
if (e.keyCode == 13) callback(inp.value, e);
});
if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) {
if (evt.relatedTarget !== null) close();
});
} else if (button = dialog.getElementsByTagName("button")[0]) {
CodeMirror.on(button, "click", function() {
close();
me.focus();
});
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
button.focus();
}
return close;
});
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom);
var buttons = dialog.getElementsByTagName("button");
var closed = false, me = this, blurring = 1;
function close() {
if (closed) return;
closed = true;
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
dialog.parentNode.removeChild(dialog);
me.focus();
}
buttons[0].focus();
for (var i = 0; i < buttons.length; ++i) {
var b = buttons[i];
(function(callback) {
CodeMirror.on(b, "click", function(e) {
CodeMirror.e_preventDefault(e);
close();
if (callback) callback(me);
});
})(callbacks[i]);
CodeMirror.on(b, "blur", function() {
--blurring;
setTimeout(function() { if (blurring <= 0) close(); }, 200);
});
CodeMirror.on(b, "focus", function() { ++blurring; });
}
});
/*
* openNotification
* Opens a notification, that can be closed with an optional timer
* (default 5000ms timer) and always closes on click.
*
* If a notification is opened while another is opened, it will close the
* currently opened one and open the new one immediately.
*/
CodeMirror.defineExtension("openNotification", function(template, options) {
closeNotification(this, close);
var dialog = dialogDiv(this, template, options && options.bottom);
var closed = false, doneTimer;
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
function close() {
if (closed) return;
closed = true;
clearTimeout(doneTimer);
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
dialog.parentNode.removeChild(dialog);
}
CodeMirror.on(dialog, 'click', function(e) {
CodeMirror.e_preventDefault(e);
close();
});
if (duration)
doneTimer = setTimeout(close, duration);
return close;
});
});
@@ -1,47 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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.defineOption("autoRefresh", false, function(cm, val) {
if (cm.state.autoRefresh) {
stopListening(cm, cm.state.autoRefresh)
cm.state.autoRefresh = null
}
if (val && cm.display.wrapper.offsetHeight == 0)
startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250})
})
function startListening(cm, state) {
function check() {
if (cm.display.wrapper.offsetHeight) {
stopListening(cm, state)
if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight)
cm.refresh()
} else {
state.timeout = setTimeout(check, state.delay)
}
}
state.timeout = setTimeout(check, state.delay)
state.hurry = function() {
clearTimeout(state.timeout)
state.timeout = setTimeout(check, 50)
}
CodeMirror.on(window, "mouseup", state.hurry)
CodeMirror.on(window, "keyup", state.hurry)
}
function stopListening(_cm, state) {
clearTimeout(state.timeout)
CodeMirror.off(window, "mouseup", state.hurry)
CodeMirror.off(window, "keyup", state.hurry)
}
});
@@ -1,6 +0,0 @@
.CodeMirror-fullscreen {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
height: auto;
z-index: 9;
}
@@ -1,41 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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.defineOption("fullScreen", false, function(cm, val, old) {
if (old == CodeMirror.Init) old = false;
if (!old == !val) return;
if (val) setFullscreen(cm);
else setNormal(cm);
});
function setFullscreen(cm) {
var wrap = cm.getWrapperElement();
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
width: wrap.style.width, height: wrap.style.height};
wrap.style.width = "";
wrap.style.height = "auto";
wrap.className += " CodeMirror-fullscreen";
document.documentElement.style.overflow = "hidden";
cm.refresh();
}
function setNormal(cm) {
var wrap = cm.getWrapperElement();
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
document.documentElement.style.overflow = "";
var info = cm.state.fullScreenRestore;
wrap.style.width = info.width; wrap.style.height = info.height;
window.scrollTo(info.scrollLeft, info.scrollTop);
cm.refresh();
}
});
@@ -1,160 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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) {
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
(document.documentMode == null || document.documentMode < 8);
var Pos = CodeMirror.Pos;
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
function bracketRegex(config) {
return config && config.bracketRegex || /[(){}[\]]/
}
function findMatchingBracket(cm, where, config) {
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
var afterCursor = config && config.afterCursor
if (afterCursor == null)
afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
var re = bracketRegex(config)
// A cursor is defined as between two characters, but in vim command mode
// (i.e. not insert mode), the cursor is visually represented as a
// highlighted box on top of the 2nd character. Otherwise, we allow matches
// from before or after the cursor.
var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) ||
re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)];
if (!match) return null;
var dir = match.charAt(1) == ">" ? 1 : -1;
if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style, config);
if (found == null) return null;
return {from: Pos(where.line, pos), to: found && found.pos,
match: found && found.ch == match.charAt(0), forward: dir > 0};
}
// bracketRegex is used to specify which type of bracket to scan
// should be a regexp, e.g. /[[\]]/
//
// Note: If "where" is on an open bracket, then this bracket is ignored.
//
// Returns false when no bracket was found, null when it reached
// maxScanLines and gave up
function scanForBracket(cm, where, dir, style, config) {
var maxScanLen = (config && config.maxScanLineLength) || 10000;
var maxScanLines = (config && config.maxScanLines) || 1000;
var stack = [];
var re = bracketRegex(config)
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
var line = cm.getLine(lineNo);
if (!line) continue;
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
if (line.length > maxScanLen) continue;
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
for (; pos != end; pos += dir) {
var ch = line.charAt(pos);
if (re.test(ch) && (style === undefined ||
(cm.getTokenTypeAt(Pos(lineNo, pos + 1)) || "") == (style || ""))) {
var match = matching[ch];
if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
else stack.pop();
}
}
}
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
}
function matchBrackets(cm, autoclear, config) {
// Disable brace matching in long lines, since it'll cause hugely slow updates
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000,
highlightNonMatching = config && config.highlightNonMatching;
var marks = [], ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
if (match && (match.match || highlightNonMatching !== false) && cm.getLine(match.from.line).length <= maxHighlightLen) {
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
}
}
if (marks.length) {
// Kludge to work around the IE bug from issue #1193, where text
// input stops going to the textarea whenever this fires.
if (ie_lt8 && cm.state.focused) cm.focus();
var clear = function() {
cm.operation(function() {
for (var i = 0; i < marks.length; i++) marks[i].clear();
});
};
if (autoclear) setTimeout(clear, 800);
else return clear;
}
}
function doMatchBrackets(cm) {
cm.operation(function() {
if (cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
});
}
function clearHighlighted(cm) {
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
}
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchBrackets);
cm.off("focus", doMatchBrackets)
cm.off("blur", clearHighlighted)
clearHighlighted(cm);
}
if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets);
cm.on("focus", doMatchBrackets)
cm.on("blur", clearHighlighted)
}
});
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
// Backwards-compatibility kludge
if (oldConfig || typeof config == "boolean") {
if (!oldConfig) {
config = config ? {strict: true} : null
} else {
oldConfig.strict = config
config = oldConfig
}
}
return findMatchingBracket(this, pos, config)
});
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
return scanForBracket(this, pos, dir, style, config);
});
});
@@ -1,159 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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";
function doFold(cm, pos, options, force) {
if (options && options.call) {
var finder = options;
options = null;
} else {
var finder = getOption(cm, options, "rangeFinder");
}
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
var minSize = getOption(cm, options, "minFoldSize");
function getRange(allowFolded) {
var range = finder(cm, pos);
if (!range || range.to.line - range.from.line < minSize) return null;
if (force === "fold") return range;
var marks = cm.findMarksAt(range.from);
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold) {
if (!allowFolded) return null;
range.cleared = true;
marks[i].clear();
}
}
return range;
}
var range = getRange(true);
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
pos = CodeMirror.Pos(pos.line - 1, 0);
range = getRange(false);
}
if (!range || range.cleared || force === "unfold") return;
var myWidget = makeWidget(cm, options, range);
CodeMirror.on(myWidget, "mousedown", function(e) {
myRange.clear();
CodeMirror.e_preventDefault(e);
});
var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget,
clearOnEnter: getOption(cm, options, "clearOnEnter"),
__isFold: true
});
myRange.on("clear", function(from, to) {
CodeMirror.signal(cm, "unfold", cm, from, to);
});
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
}
function makeWidget(cm, options, range) {
var widget = getOption(cm, options, "widget");
if (typeof widget == "function") {
widget = widget(range.from, range.to);
}
if (typeof widget == "string") {
var text = document.createTextNode(widget);
widget = document.createElement("span");
widget.appendChild(text);
widget.className = "CodeMirror-foldmarker";
} else if (widget) {
widget = widget.cloneNode(true)
}
return widget;
}
// Clumsy backwards-compatible interface
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
};
// New-style interface
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
doFold(this, pos, options, force);
});
CodeMirror.defineExtension("isFolded", function(pos) {
var marks = this.findMarksAt(pos);
for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold) return true;
});
CodeMirror.commands.toggleFold = function(cm) {
cm.foldCode(cm.getCursor());
};
CodeMirror.commands.fold = function(cm) {
cm.foldCode(cm.getCursor(), null, "fold");
};
CodeMirror.commands.unfold = function(cm) {
cm.foldCode(cm.getCursor(), { scanUp: false }, "unfold");
};
CodeMirror.commands.foldAll = function(cm) {
cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "fold");
});
};
CodeMirror.commands.unfoldAll = function(cm) {
cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "unfold");
});
};
CodeMirror.registerHelper("fold", "combine", function() {
var funcs = Array.prototype.slice.call(arguments, 0);
return function(cm, start) {
for (var i = 0; i < funcs.length; ++i) {
var found = funcs[i](cm, start);
if (found) return found;
}
};
});
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
var helpers = cm.getHelpers(start, "fold");
for (var i = 0; i < helpers.length; i++) {
var cur = helpers[i](cm, start);
if (cur) return cur;
}
});
var defaultOptions = {
rangeFinder: CodeMirror.fold.auto,
widget: "\u2194",
minFoldSize: 0,
scanUp: false,
clearOnEnter: true
};
CodeMirror.defineOption("foldOptions", null);
function getOption(cm, options, name) {
if (options && options[name] !== undefined)
return options[name];
var editorOptions = cm.options.foldOptions;
if (editorOptions && editorOptions[name] !== undefined)
return editorOptions[name];
return defaultOptions[name];
}
CodeMirror.defineExtension("foldOption", function(options, name) {
return getOption(this, options, name);
});
});
@@ -1,20 +0,0 @@
.CodeMirror-foldmarker {
color: blue;
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
font-family: arial;
line-height: .3;
cursor: pointer;
}
.CodeMirror-foldgutter {
width: .7em;
}
.CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded {
cursor: pointer;
}
.CodeMirror-foldgutter-open:after {
content: "\25BE";
}
.CodeMirror-foldgutter-folded:after {
content: "\25B8";
}
@@ -1,169 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./foldcode"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./foldcode"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.clearGutter(cm.state.foldGutter.options.gutter);
cm.state.foldGutter = null;
cm.off("gutterClick", onGutterClick);
cm.off("changes", onChange);
cm.off("viewportChange", onViewportChange);
cm.off("fold", onFold);
cm.off("unfold", onFold);
cm.off("swapDoc", onChange);
cm.off("optionChange", optionChange);
}
if (val) {
cm.state.foldGutter = new State(parseOptions(val));
updateInViewport(cm);
cm.on("gutterClick", onGutterClick);
cm.on("changes", onChange);
cm.on("viewportChange", onViewportChange);
cm.on("fold", onFold);
cm.on("unfold", onFold);
cm.on("swapDoc", onChange);
cm.on("optionChange", optionChange);
}
});
var Pos = CodeMirror.Pos;
function State(options) {
this.options = options;
this.from = this.to = 0;
}
function parseOptions(opts) {
if (opts === true) opts = {};
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
return opts;
}
function isFolded(cm, line) {
var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold) {
var fromPos = marks[i].find(-1);
if (fromPos && fromPos.line === line)
return marks[i];
}
}
}
function marker(spec) {
if (typeof spec == "string") {
var elt = document.createElement("div");
elt.className = spec + " CodeMirror-guttermarker-subtle";
return elt;
} else {
return spec.cloneNode(true);
}
}
function updateFoldInfo(cm, from, to) {
var opts = cm.state.foldGutter.options, cur = from - 1;
var minSize = cm.foldOption(opts, "minFoldSize");
var func = cm.foldOption(opts, "rangeFinder");
// we can reuse the built-in indicator element if its className matches the new state
var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded);
var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen);
cm.eachLine(from, to, function(line) {
++cur;
var mark = null;
var old = line.gutterMarkers;
if (old) old = old[opts.gutter];
if (isFolded(cm, cur)) {
if (clsFolded && old && clsFolded.test(old.className)) return;
mark = marker(opts.indicatorFolded);
} else {
var pos = Pos(cur, 0);
var range = func && func(cm, pos);
if (range && range.to.line - range.from.line >= minSize) {
if (clsOpen && old && clsOpen.test(old.className)) return;
mark = marker(opts.indicatorOpen);
}
}
if (!mark && !old) return;
cm.setGutterMarker(line, opts.gutter, mark);
});
}
// copied from CodeMirror/src/util/dom.js
function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
function updateInViewport(cm) {
var vp = cm.getViewport(), state = cm.state.foldGutter;
if (!state) return;
cm.operation(function() {
updateFoldInfo(cm, vp.from, vp.to);
});
state.from = vp.from; state.to = vp.to;
}
function onGutterClick(cm, line, gutter) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
if (gutter != opts.gutter) return;
var folded = isFolded(cm, line);
if (folded) folded.clear();
else cm.foldCode(Pos(line, 0), opts);
}
function optionChange(cm, option) {
if (option == "mode") onChange(cm)
}
function onChange(cm) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
state.from = state.to = 0;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
}
function onViewportChange(cm) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() {
var vp = cm.getViewport();
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
updateInViewport(cm);
} else {
cm.operation(function() {
if (vp.from < state.from) {
updateFoldInfo(cm, vp.from, state.from);
state.from = vp.from;
}
if (vp.to > state.to) {
updateFoldInfo(cm, state.to, vp.to);
state.to = vp.to;
}
});
}
}, opts.updateViewportTimeSpan || 400);
}
function onFold(cm, from) {
var state = cm.state.foldGutter;
if (!state) return;
var line = from.line;
if (line >= state.from && line < state.to)
updateFoldInfo(cm, line, line + 1);
}
});
@@ -1,48 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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";
function lineIndent(cm, lineNo) {
var text = cm.getLine(lineNo)
var spaceTo = text.search(/\S/)
if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
return -1
return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
}
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var myIndent = lineIndent(cm, start.line)
if (myIndent < 0) return
var lastLineInFold = null
// Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end.
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var indent = lineIndent(cm, i)
if (indent == -1) {
} else if (indent > myIndent) {
// Lines with a greater indent are considered part of the block.
lastLineInFold = i;
} else {
// If this line has non-space, non-comment content, and is
// indented less or equal to the start line, it is the start of
// another block.
break;
}
}
if (lastLineInFold) return {
from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
};
});
});
@@ -1,2 +0,0 @@
/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,function(e){"use strict";function t(e){return null==e}var n={isNothing:t,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:t(e)?[]:[e]},repeat:function(e,t){var n,i="";for(n=0;n<t;n+=1)i+=e;return i},isNegativeZero:function(e){return 0===e&&Number.NEGATIVE_INFINITY===1/e},extend:function(e,t){var n,i,r,o;if(t)for(n=0,i=(o=Object.keys(t)).length;n<i;n+=1)e[r=o[n]]=t[r];return e}};function i(e,t){var n="",i=e.reason||"(unknown reason)";return e.mark?(e.mark.name&&(n+='in "'+e.mark.name+'" '),n+="("+(e.mark.line+1)+":"+(e.mark.column+1)+")",!t&&e.mark.snippet&&(n+="\n\n"+e.mark.snippet),i+" "+n):i}function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=i(this,!1),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){return this.name+": "+i(this,e)};var o=r;function a(e,t,n,i,r){var o="",a="",l=Math.floor(r/2)-1;return i-t>l&&(t=i-l+(o=" ... ").length),n-i>l&&(n=i+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:i-t+o.length}}function l(e,t){return n.repeat(" ",t-e.length)+e}var c=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,r=/\r?\n|\r|\0/g,o=[0],c=[],s=-1;i=r.exec(e.buffer);)c.push(i.index),o.push(i.index+i[0].length),e.position<=i.index&&s<0&&(s=o.length-2);s<0&&(s=o.length-1);var u,p,f="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(u=1;u<=t.linesBefore&&!(s-u<0);u++)p=a(e.buffer,o[s-u],c[s-u],e.position-(o[s]-o[s-u]),h),f=n.repeat(" ",t.indent)+l((e.line-u+1).toString(),d)+" | "+p.str+"\n"+f;for(p=a(e.buffer,o[s],c[s],e.position,h),f+=n.repeat(" ",t.indent)+l((e.line+1).toString(),d)+" | "+p.str+"\n",f+=n.repeat("-",t.indent+d+3+p.pos)+"^\n",u=1;u<=t.linesAfter&&!(s+u>=c.length);u++)p=a(e.buffer,o[s+u],c[s+u],e.position-(o[s]-o[s+u]),h),f+=n.repeat(" ",t.indent)+l((e.line+u+1).toString(),d)+" | "+p.str+"\n";return f.replace(/\n$/,"")},s=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],u=["scalar","sequence","mapping"];var p=function(e,t){if(t=t||{},Object.keys(t).forEach(function(t){if(-1===s.indexOf(t))throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')}),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach(function(n){e[n].forEach(function(e){t[String(e)]=n})}),t}(t.styleAliases||null),-1===u.indexOf(this.kind))throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function f(e,t){var n=[];return e[t].forEach(function(e){var t=n.length;n.forEach(function(n,i){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=i)}),n[t]=e}),n}function d(e){return this.extend(e)}d.prototype.extend=function(e){var t=[],n=[];if(e instanceof p)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new o("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach(function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new o("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new o("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")}),n.forEach(function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.")});var i=Object.create(d.prototype);return i.implicit=(this.implicit||[]).concat(t),i.explicit=(this.explicit||[]).concat(n),i.compiledImplicit=f(i,"implicit"),i.compiledExplicit=f(i,"explicit"),i.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kiLine truncated
@@ -1,79 +0,0 @@
/* The lint marker gutter */
.CodeMirror-lint-markers {
width: 16px;
}
.CodeMirror-lint-tooltip {
background-color: #ffd;
border: 1px solid black;
border-radius: 4px 4px 4px 4px;
color: black;
font-family: monospace;
font-size: 10pt;
overflow: hidden;
padding: 2px 5px;
position: fixed;
white-space: pre;
white-space: pre-wrap;
z-index: 100;
max-width: 600px;
opacity: 0;
transition: opacity .4s;
-moz-transition: opacity .4s;
-webkit-transition: opacity .4s;
-o-transition: opacity .4s;
-ms-transition: opacity .4s;
}
.CodeMirror-lint-mark {
background-position: left bottom;
background-repeat: repeat-x;
}
.CodeMirror-lint-mark-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
}
.CodeMirror-lint-mark-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
}
.CodeMirror-lint-marker {
background-position: center center;
background-repeat: no-repeat;
cursor: pointer;
display: inline-block;
height: 16px;
width: 16px;
vertical-align: middle;
position: relative;
}
.CodeMirror-lint-message {
padding-left: 18px;
background-position: top left;
background-repeat: no-repeat;
}
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
}
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
}
.CodeMirror-lint-marker-multiple {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
background-repeat: no-repeat;
background-position: right bottom;
width: 100%; height: 100%;
}
.CodeMirror-lint-line-error {
background-color: rgba(183, 76, 81, 0.08);
}
.CodeMirror-lint-line-warning {
background-color: rgba(255, 211, 0, 0.1);
}
@@ -1,288 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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";
var GUTTER_ID = "CodeMirror-lint-markers";
var LINT_LINE_ID = "CodeMirror-lint-line-";
function showTooltip(cm, e, content) {
var tt = document.createElement("div");
tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme;
tt.appendChild(content.cloneNode(true));
if (cm.state.lint.options.selfContain)
cm.getWrapperElement().appendChild(tt);
else
document.body.appendChild(tt);
function position(e) {
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
var top = Math.max(0, e.clientY - tt.offsetHeight - 5);
var left = Math.max(0, Math.min(e.clientX + 5, tt.ownerDocument.defaultView.innerWidth - tt.offsetWidth));
tt.style.top = top + "px"
tt.style.left = left + "px";
}
CodeMirror.on(document, "mousemove", position);
position(e);
if (tt.style.opacity != null) tt.style.opacity = 1;
return tt;
}
function rm(elt) {
if (elt.parentNode) elt.parentNode.removeChild(elt);
}
function hideTooltip(tt) {
if (!tt.parentNode) return;
if (tt.style.opacity == null) rm(tt);
tt.style.opacity = 0;
setTimeout(function() { rm(tt); }, 600);
}
function showTooltipFor(cm, e, content, node) {
var tooltip = showTooltip(cm, e, content);
function hide() {
CodeMirror.off(node, "mouseout", hide);
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
}
var poll = setInterval(function() {
if (tooltip) for (var n = node;; n = n.parentNode) {
if (n && n.nodeType == 11) n = n.host;
if (n == document.body) return;
if (!n) { hide(); break; }
}
if (!tooltip) return clearInterval(poll);
}, 400);
CodeMirror.on(node, "mouseout", hide);
}
function LintState(cm, conf, hasGutter) {
this.marked = [];
if (conf instanceof Function) conf = {getAnnotations: conf};
if (!conf || conf === true) conf = {};
this.options = {};
this.linterOptions = conf.options || {};
for (var prop in defaults) this.options[prop] = defaults[prop];
for (var prop in conf) {
if (defaults.hasOwnProperty(prop)) {
if (conf[prop] != null) this.options[prop] = conf[prop];
} else if (!conf.options) {
this.linterOptions[prop] = conf[prop];
}
}
this.timeout = null;
this.hasGutter = hasGutter;
this.onMouseOver = function(e) { onMouseOver(cm, e); };
this.waitingFor = 0
}
var defaults = {
highlightLines: false,
tooltips: true,
delay: 500,
lintOnChange: true,
getAnnotations: null,
async: false,
selfContain: null,
formatAnnotation: null,
onUpdateLinting: null
}
function clearMarks(cm) {
var state = cm.state.lint;
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
if (state.options.highlightLines) clearErrorLines(cm);
for (var i = 0; i < state.marked.length; ++i)
state.marked[i].clear();
state.marked.length = 0;
}
function clearErrorLines(cm) {
cm.eachLine(function(line) {
var has = line.wrapClass && /\bCodeMirror-lint-line-\w+\b/.exec(line.wrapClass);
if (has) cm.removeLineClass(line, "wrap", has[0]);
})
}
function makeMarker(cm, labels, severity, multiple, tooltips) {
var marker = document.createElement("div"), inner = marker;
marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity;
if (multiple) {
inner = marker.appendChild(document.createElement("div"));
inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple";
}
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
showTooltipFor(cm, e, labels, inner);
});
return marker;
}
function getMaxSeverity(a, b) {
if (a == "error") return a;
else return b;
}
function groupByLine(annotations) {
var lines = [];
for (var i = 0; i < annotations.length; ++i) {
var ann = annotations[i], line = ann.from.line;
(lines[line] || (lines[line] = [])).push(ann);
}
return lines;
}
function annotationTooltip(ann) {
var severity = ann.severity;
if (!severity) severity = "error";
var tip = document.createElement("div");
tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity;
if (typeof ann.messageHTML != 'undefined') {
tip.innerHTML = ann.messageHTML;
} else {
tip.appendChild(document.createTextNode(ann.message));
}
return tip;
}
function lintAsync(cm, getAnnotations) {
var state = cm.state.lint
var id = ++state.waitingFor
function abort() {
id = -1
cm.off("change", abort)
}
cm.on("change", abort)
getAnnotations(cm.getValue(), function(annotations, arg2) {
cm.off("change", abort)
if (state.waitingFor != id) return
if (arg2 && annotations instanceof CodeMirror) annotations = arg2
cm.operation(function() {updateLinting(cm, annotations)})
}, state.linterOptions, cm);
}
function startLinting(cm) {
var state = cm.state.lint;
if (!state) return;
var options = state.options;
/*
* Passing rules in `options` property prevents JSHint (and other linters) from complaining
* about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc.
*/
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
if (!getAnnotations) return;
if (options.async || getAnnotations.async) {
lintAsync(cm, getAnnotations)
} else {
var annotations = getAnnotations(cm.getValue(), state.linterOptions, cm);
if (!annotations) return;
if (annotations.then) annotations.then(function(issues) {
cm.operation(function() {updateLinting(cm, issues)})
});
else cm.operation(function() {updateLinting(cm, annotations)})
}
}
function updateLinting(cm, annotationsNotSorted) {
var state = cm.state.lint;
if (!state) return;
var options = state.options;
clearMarks(cm);
var annotations = groupByLine(annotationsNotSorted);
for (var line = 0; line < annotations.length; ++line) {
var anns = annotations[line];
if (!anns) continue;
var maxSeverity = null;
var tipLabel = state.hasGutter && document.createDocumentFragment();
for (var i = 0; i < anns.length; ++i) {
var ann = anns[i];
var severity = ann.severity;
if (!severity) severity = "error";
maxSeverity = getMaxSeverity(maxSeverity, severity);
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity,
__annotation: ann
}));
}
if (state.hasGutter)
cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1,
options.tooltips));
if (options.highlightLines)
cm.addLineClass(line, "wrap", LINT_LINE_ID + maxSeverity);
}
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
}
function onChange(cm) {
var state = cm.state.lint;
if (!state) return;
clearTimeout(state.timeout);
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay);
}
function popupTooltips(cm, annotations, e) {
var target = e.target || e.srcElement;
var tooltip = document.createDocumentFragment();
for (var i = 0; i < annotations.length; i++) {
var ann = annotations[i];
tooltip.appendChild(annotationTooltip(ann));
}
showTooltipFor(cm, e, tooltip, target);
}
function onMouseOver(cm, e) {
var target = e.target || e.srcElement;
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
var annotations = [];
for (var i = 0; i < spans.length; ++i) {
var ann = spans[i].__annotation;
if (ann) annotations.push(ann);
}
if (annotations.length) popupTooltips(cm, annotations, e);
}
CodeMirror.defineOption("lint", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
clearMarks(cm);
if (cm.state.lint.options.lintOnChange !== false)
cm.off("change", onChange);
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
clearTimeout(cm.state.lint.timeout);
delete cm.state.lint;
}
if (val) {
var gutters = cm.getOption("gutters"), hasLintGutter = false;
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
var state = cm.state.lint = new LintState(cm, val, hasLintGutter);
if (state.options.lintOnChange)
cm.on("change", onChange);
if (state.options.tooltips != false && state.options.tooltips != "gutter")
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
startLinting(cm);
}
});
CodeMirror.defineExtension("performLint", function() {
startLinting(this);
});
});
@@ -1,41 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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";
// Depends on js-yaml.js from https://github.com/nodeca/js-yaml
// declare global: jsyaml
CodeMirror.registerHelper("lint", "yaml", function(text) {
var found = [];
if (!window.jsyaml) {
if (window.console) {
window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run.");
}
return found;
}
try { jsyaml.loadAll(text); }
catch(e) {
var loc = e.mark,
// js-yaml YAMLException doesn't always provide an accurate lineno
// e.g., when there are multiple yaml docs
// ---
// ---
// foo:bar
from = loc ? CodeMirror.Pos(loc.line, loc.column) : CodeMirror.Pos(0, 0),
to = from;
found.push({ from: from, to: to, message: e.message });
}
return found;
});
});
@@ -1,55 +0,0 @@
var diff_match_patch=function(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=.5;this.Patch_Margin=4;this.Match_MaxBits=32},DIFF_DELETE=-1,DIFF_INSERT=1,DIFF_EQUAL=0;diff_match_patch.Diff=function(a,b){this[0]=a;this[1]=b};diff_match_patch.Diff.prototype.length=2;diff_match_patch.Diff.prototype.toString=function(){return this[0]+","+this[1]};
diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[new diff_match_patch.Diff(DIFF_EQUAL,a)]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);f=this.diff_commonSuffix(a,b);var g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,
b.length-f);a=this.diff_compute_(a,b,e,d);c&&a.unshift(new diff_match_patch.Diff(DIFF_EQUAL,c));g&&a.push(new diff_match_patch.Diff(DIFF_EQUAL,g));this.diff_cleanupMerge(a);return a};
diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[new diff_match_patch.Diff(DIFF_INSERT,b)];if(!b)return[new diff_match_patch.Diff(DIFF_DELETE,a)];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[new diff_match_patch.Diff(DIFF_INSERT,e.substring(0,g)),new diff_match_patch.Diff(DIFF_EQUAL,f),new diff_match_patch.Diff(DIFF_INSERT,e.substring(g+f.length))],a.length>b.length&&(c[0][0]=c[2][0]=DIFF_DELETE),c):1==f.length?[new diff_match_patch.Diff(DIFF_DELETE,
a),new diff_match_patch.Diff(DIFF_INSERT,b)]:(e=this.diff_halfMatch_(a,b))?(b=e[1],f=e[3],a=e[4],e=this.diff_main(e[0],e[2],c,d),c=this.diff_main(b,f,c,d),e.concat([new diff_match_patch.Diff(DIFF_EQUAL,a)],c)):c&&100<a.length&&100<b.length?this.diff_lineMode_(a,b,d):this.diff_bisect_(a,b,d)};
diff_match_patch.prototype.diff_lineMode_=function(a,b,c){var d=this.diff_linesToChars_(a,b);a=d.chars1;b=d.chars2;d=d.lineArray;a=this.diff_main(a,b,!1,c);this.diff_charsToLines_(a,d);this.diff_cleanupSemantic(a);a.push(new diff_match_patch.Diff(DIFF_EQUAL,""));for(var e=d=b=0,f="",g="";b<a.length;){switch(a[b][0]){case DIFF_INSERT:e++;g+=a[b][1];break;case DIFF_DELETE:d++;f+=a[b][1];break;case DIFF_EQUAL:if(1<=d&&1<=e){a.splice(b-d-e,d+e);b=b-d-e;d=this.diff_main(f,g,!1,c);for(e=d.length-1;0<=e;e--)a.splice(b,
0,d[e]);b+=d.length}d=e=0;g=f=""}b++}a.pop();return a};
diff_match_patch.prototype.diff_bisect_=function(a,b,c){for(var d=a.length,e=b.length,f=Math.ceil((d+e)/2),g=2*f,h=Array(g),l=Array(g),k=0;k<g;k++)h[k]=-1,l[k]=-1;h[f+1]=0;l[f+1]=0;k=d-e;for(var m=0!=k%2,p=0,x=0,w=0,q=0,t=0;t<f&&!((new Date).getTime()>c);t++){for(var v=-t+p;v<=t-x;v+=2){var n=f+v;var r=v==-t||v!=t&&h[n-1]<h[n+1]?h[n+1]:h[n-1]+1;for(var y=r-v;r<d&&y<e&&a.charAt(r)==b.charAt(y);)r++,y++;h[n]=r;if(r>d)x+=2;else if(y>e)p+=2;else if(m&&(n=f+k-v,0<=n&&n<g&&-1!=l[n])){var u=d-l[n];if(r>=
u)return this.diff_bisectSplit_(a,b,r,y,c)}}for(v=-t+w;v<=t-q;v+=2){n=f+v;u=v==-t||v!=t&&l[n-1]<l[n+1]?l[n+1]:l[n-1]+1;for(r=u-v;u<d&&r<e&&a.charAt(d-u-1)==b.charAt(e-r-1);)u++,r++;l[n]=u;if(u>d)q+=2;else if(r>e)w+=2;else if(!m&&(n=f+k-v,0<=n&&n<g&&-1!=h[n]&&(r=h[n],y=f+r-n,u=d-u,r>=u)))return this.diff_bisectSplit_(a,b,r,y,c)}}return[new diff_match_patch.Diff(DIFF_DELETE,a),new diff_match_patch.Diff(DIFF_INSERT,b)]};
diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)};
diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,g=-1,h=d.length;g<a.length-1;){g=a.indexOf("\n",c);-1==g&&(g=a.length-1);var l=a.substring(c,g+1);(e.hasOwnProperty?e.hasOwnProperty(l):void 0!==e[l])?b+=String.fromCharCode(e[l]):(h==f&&(l=a.substring(c),g=a.length),b+=String.fromCharCode(h),e[l]=h,d[h++]=l);c=g+1}return b}var d=[],e={};d[0]="";var f=4E4,g=c(a);f=65535;var h=c(b);return{chars1:g,chars2:h,lineArray:d}};
diff_match_patch.prototype.diff_charsToLines_=function(a,b){for(var c=0;c<a.length;c++){for(var d=a[c][1],e=[],f=0;f<d.length;f++)e[f]=b[d.charCodeAt(f)];a[c][1]=e.join("")}};diff_match_patch.prototype.diff_commonPrefix=function(a,b){if(!a||!b||a.charAt(0)!=b.charAt(0))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(f,e)==b.substring(f,e)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
diff_match_patch.prototype.diff_commonSuffix=function(a,b){if(!a||!b||a.charAt(a.length-1)!=b.charAt(b.length-1))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(a.length-e,a.length-f)==b.substring(b.length-e,b.length-f)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
diff_match_patch.prototype.diff_commonOverlap_=function(a,b){var c=a.length,d=b.length;if(0==c||0==d)return 0;c>d?a=a.substring(c-d):c<d&&(b=b.substring(0,c));c=Math.min(c,d);if(a==b)return c;d=0;for(var e=1;;){var f=a.substring(c-e);f=b.indexOf(f);if(-1==f)return d;e+=f;if(0==f||a.substring(c-e)==b.substring(0,e))d=e,e++}};
diff_match_patch.prototype.diff_halfMatch_=function(a,b){function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1,g="",h,k,l,m;-1!=(e=b.indexOf(d,e+1));){var p=f.diff_commonPrefix(a.substring(c),b.substring(e)),u=f.diff_commonSuffix(a.substring(0,c),b.substring(0,e));g.length<u+p&&(g=b.substring(e-u,e)+b.substring(e,e+p),h=a.substring(0,c-u),k=a.substring(c+p),l=b.substring(0,e-u),m=b.substring(e+p))}return 2*g.length>=a.length?[h,k,l,m,g]:null}if(0>=this.Diff_Timeout)return null;
var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.length<d.length)return null;var f=this,g=c(d,e,Math.ceil(d.length/4));d=c(d,e,Math.ceil(d.length/2));if(g||d)g=d?g?g[4].length>d[4].length?g:d:d:g;else return null;if(a.length>b.length){d=g[0];e=g[1];var h=g[2];var l=g[3]}else h=g[0],l=g[1],d=g[2],e=g[3];return[d,e,h,l,g[4]]};
diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,l=0,k=0;f<a.length;)a[f][0]==DIFF_EQUAL?(c[d++]=f,g=l,h=k,k=l=0,e=a[f][1]):(a[f][0]==DIFF_INSERT?l+=a[f][1].length:k+=a[f][1].length,e&&e.length<=Math.max(g,h)&&e.length<=Math.max(l,k)&&(a.splice(c[d-1],0,new diff_match_patch.Diff(DIFF_DELETE,e)),a[c[d-1]+1][0]=DIFF_INSERT,d--,d--,f=0<d?c[d-1]:-1,k=l=h=g=0,e=null,b=!0)),f++;b&&this.diff_cleanupMerge(a);this.diff_cleanupSemanticLossless(a);for(f=1;f<
a.length;){if(a[f-1][0]==DIFF_DELETE&&a[f][0]==DIFF_INSERT){b=a[f-1][1];c=a[f][1];d=this.diff_commonOverlap_(b,c);e=this.diff_commonOverlap_(c,b);if(d>=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,new diff_match_patch.Diff(DIFF_EQUAL,c.substring(0,d))),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,new diff_match_patch.Diff(DIFF_EQUAL,b.substring(0,e))),a[f-1][0]=DIFF_INSERT,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=DIFF_DELETE,
a[f+1][1]=b.substring(e),f++;f++}f++}};
diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_);c=g&&c.match(diff_match_patch.linebreakRegex_);d=h&&d.match(diff_match_patch.linebreakRegex_);var k=c&&a.match(diff_match_patch.blanklineEndRegex_),l=d&&b.match(diff_match_patch.blanklineStartRegex_);
return k||l?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c<a.length-1;){if(a[c-1][0]==DIFF_EQUAL&&a[c+1][0]==DIFF_EQUAL){var d=a[c-1][1],e=a[c][1],f=a[c+1][1],g=this.diff_commonSuffix(d,e);if(g){var h=e.substring(e.length-g);d=d.substring(0,d.length-g);e=h+e.substring(0,e.length-g);f=h+f}g=d;h=e;for(var l=f,k=b(d,e)+b(e,f);e.charAt(0)===f.charAt(0);){d+=e.charAt(0);e=e.substring(1)+f.charAt(0);f=f.substring(1);var m=b(d,e)+b(e,f);m>=k&&(k=m,g=d,h=e,l=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-
1,1),c--),a[c][1]=h,l?a[c+1][1]=l:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,l=!1,k=!1;f<a.length;)a[f][0]==DIFF_EQUAL?(a[f][1].length<this.Diff_EditCost&&(l||k)?(c[d++]=f,g=l,h=k,e=a[f][1]):(d=0,e=null),l=k=!1):(a[f][0]==DIFF_DELETE?k=!0:l=!0,e&&(g&&h&&l&&k||e.length<this.Diff_EditCost/2&&3==g+h+l+k)&&(a.splice(c[d-1],0,new diff_match_patch.Diff(DIFF_DELETE,e)),a[c[d-1]+1][0]=DIFF_INSERT,d--,e=null,g&&h?(l=k=!0,d=0):(d--,f=0<d?c[d-1]:-1,l=k=!1),b=!0)),f++;b&&this.diff_cleanupMerge(a)};
diff_match_patch.prototype.diff_cleanupMerge=function(a){a.push(new diff_match_patch.Diff(DIFF_EQUAL,""));for(var b=0,c=0,d=0,e="",f="",g;b<a.length;)switch(a[b][0]){case DIFF_INSERT:d++;f+=a[b][1];b++;break;case DIFF_DELETE:c++;e+=a[b][1];b++;break;case DIFF_EQUAL:1<c+d?(0!==c&&0!==d&&(g=this.diff_commonPrefix(f,e),0!==g&&(0<b-c-d&&a[b-c-d-1][0]==DIFF_EQUAL?a[b-c-d-1][1]+=f.substring(0,g):(a.splice(0,0,new diff_match_patch.Diff(DIFF_EQUAL,f.substring(0,g))),b++),f=f.substring(g),e=e.substring(g)),
g=this.diff_commonSuffix(f,e),0!==g&&(a[b][1]=f.substring(f.length-g)+a[b][1],f=f.substring(0,f.length-g),e=e.substring(0,e.length-g))),b-=c+d,a.splice(b,c+d),e.length&&(a.splice(b,0,new diff_match_patch.Diff(DIFF_DELETE,e)),b++),f.length&&(a.splice(b,0,new diff_match_patch.Diff(DIFF_INSERT,f)),b++),b++):0!==b&&a[b-1][0]==DIFF_EQUAL?(a[b-1][1]+=a[b][1],a.splice(b,1)):b++,c=d=0,f=e=""}""===a[a.length-1][1]&&a.pop();c=!1;for(b=1;b<a.length-1;)a[b-1][0]==DIFF_EQUAL&&a[b+1][0]==DIFF_EQUAL&&(a[b][1].substring(a[b][1].length-
a[b-1][1].length)==a[b-1][1]?(a[b][1]=a[b-1][1]+a[b][1].substring(0,a[b][1].length-a[b-1][1].length),a[b+1][1]=a[b-1][1]+a[b+1][1],a.splice(b-1,1),c=!0):a[b][1].substring(0,a[b+1][1].length)==a[b+1][1]&&(a[b-1][1]+=a[b+1][1],a[b][1]=a[b][1].substring(a[b+1][1].length)+a[b+1][1],a.splice(b+1,1),c=!0)),b++;c&&this.diff_cleanupMerge(a)};
diff_match_patch.prototype.diff_xIndex=function(a,b){var c=0,d=0,e=0,f=0,g;for(g=0;g<a.length;g++){a[g][0]!==DIFF_INSERT&&(c+=a[g][1].length);a[g][0]!==DIFF_DELETE&&(d+=a[g][1].length);if(c>b)break;e=c;f=d}return a.length!=g&&a[g][0]===DIFF_DELETE?f:f+(b-e)};
diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=/</g,e=/>/g,f=/\n/g,g=0;g<a.length;g++){var h=a[g][0],l=a[g][1].replace(c,"&amp;").replace(d,"&lt;").replace(e,"&gt;").replace(f,"&para;<br>");switch(h){case DIFF_INSERT:b[g]='<ins style="background:#e6ffe6;">'+l+"</ins>";break;case DIFF_DELETE:b[g]='<del style="background:#ffe6e6;">'+l+"</del>";break;case DIFF_EQUAL:b[g]="<span>"+l+"</span>"}}return b.join("")};
diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;c<a.length;c++)a[c][0]!==DIFF_INSERT&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_text2=function(a){for(var b=[],c=0;c<a.length;c++)a[c][0]!==DIFF_DELETE&&(b[c]=a[c][1]);return b.join("")};
diff_match_patch.prototype.diff_levenshtein=function(a){for(var b=0,c=0,d=0,e=0;e<a.length;e++){var f=a[e][1];switch(a[e][0]){case DIFF_INSERT:c+=f.length;break;case DIFF_DELETE:d+=f.length;break;case DIFF_EQUAL:b+=Math.max(c,d),d=c=0}}return b+=Math.max(c,d)};
diff_match_patch.prototype.diff_toDelta=function(a){for(var b=[],c=0;c<a.length;c++)switch(a[c][0]){case DIFF_INSERT:b[c]="+"+encodeURI(a[c][1]);break;case DIFF_DELETE:b[c]="-"+a[c][1].length;break;case DIFF_EQUAL:b[c]="="+a[c][1].length}return b.join("\t").replace(/%20/g," ")};
diff_match_patch.prototype.diff_fromDelta=function(a,b){for(var c=[],d=0,e=0,f=b.split(/\t/g),g=0;g<f.length;g++){var h=f[g].substring(1);switch(f[g].charAt(0)){case "+":try{c[d++]=new diff_match_patch.Diff(DIFF_INSERT,decodeURI(h))}catch(k){throw Error("Illegal escape in diff_fromDelta: "+h);}break;case "-":case "=":var l=parseInt(h,10);if(isNaN(l)||0>l)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=l);"="==f[g].charAt(0)?c[d++]=new diff_match_patch.Diff(DIFF_EQUAL,h):c[d++]=
new diff_match_patch.Diff(DIFF_DELETE,h);break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return f.Match_Distance?e+g/f.Match_Distance:g?1:e}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));var l=1<<b.length-1;h=-1;for(var k,m,p=b.length+a.length,x,w=0;w<b.length;w++){k=0;for(m=p;k<m;)d(w,
c+m)<=g?k=m:p=m,m=Math.floor((p-k)/2+k);p=m;k=Math.max(1,c-m+1);var q=Math.min(c+m,a.length)+b.length;m=Array(q+2);for(m[q+1]=(1<<w)-1;q>=k;q--){var t=e[a.charAt(q-1)];m[q]=0===w?(m[q+1]<<1|1)&t:(m[q+1]<<1|1)&t|(x[q+1]|x[q])<<1|1|x[q+1];if(m[q]&l&&(t=d(w,q-1),t<=g))if(g=t,h=q-1,h>c)k=Math.max(1,2*c-h);else break}if(d(w+1,c)>g)break;x=m}return h};
diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c<a.length;c++)b[a.charAt(c)]=0;for(c=0;c<a.length;c++)b[a.charAt(c)]|=1<<a.length-c-1;return b};
diff_match_patch.prototype.patch_addContext_=function(a,b){if(0!=b.length){if(null===a.start2)throw Error("patch not initialized");for(var c=b.substring(a.start2,a.start2+a.length1),d=0;b.indexOf(c)!=b.lastIndexOf(c)&&c.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)d+=this.Patch_Margin,c=b.substring(a.start2-d,a.start2+a.length1+d);d+=this.Patch_Margin;(c=b.substring(a.start2-d,a.start2))&&a.diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL,c));(d=b.substring(a.start2+a.length1,
a.start2+a.length1+d))&&a.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,d));a.start1-=c.length;a.start2-=c.length;a.length1+=c.length+d.length;a.length2+=c.length+d.length}};
diff_match_patch.prototype.patch_make=function(a,b,c){if("string"==typeof a&&"string"==typeof b&&"undefined"==typeof c){var d=a;b=this.diff_main(d,b,!0);2<b.length&&(this.diff_cleanupSemantic(b),this.diff_cleanupEfficiency(b))}else if(a&&"object"==typeof a&&"undefined"==typeof b&&"undefined"==typeof c)b=a,d=this.diff_text1(b);else if("string"==typeof a&&b&&"object"==typeof b&&"undefined"==typeof c)d=a;else if("string"==typeof a&&"string"==typeof b&&c&&"object"==typeof c)d=a,b=c;else throw Error("Unknown call format to patch_make.");
if(0===b.length)return[];c=[];a=new diff_match_patch.patch_obj;for(var e=0,f=0,g=0,h=d,l=0;l<b.length;l++){var k=b[l][0],m=b[l][1];e||k===DIFF_EQUAL||(a.start1=f,a.start2=g);switch(k){case DIFF_INSERT:a.diffs[e++]=b[l];a.length2+=m.length;d=d.substring(0,g)+m+d.substring(g);break;case DIFF_DELETE:a.length1+=m.length;a.diffs[e++]=b[l];d=d.substring(0,g)+d.substring(g+m.length);break;case DIFF_EQUAL:m.length<=2*this.Patch_Margin&&e&&b.length!=l+1?(a.diffs[e++]=b[l],a.length1+=m.length,a.length2+=m.length):
m.length>=2*this.Patch_Margin&&e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}k!==DIFF_INSERT&&(f+=m.length);k!==DIFF_DELETE&&(g+=m.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};
diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new diff_match_patch.patch_obj;e.diffs=[];for(var f=0;f<d.diffs.length;f++)e.diffs[f]=new diff_match_patch.Diff(d.diffs[f][0],d.diffs[f][1]);e.start1=d.start1;e.start2=d.start2;e.length1=d.length1;e.length2=d.length2;b[c]=e}return b};
diff_match_patch.prototype.patch_apply=function(a,b){if(0==a.length)return[b,[]];a=this.patch_deepCopy(a);var c=this.patch_addPadding(a);b=c+b+c;this.patch_splitMax(a);for(var d=0,e=[],f=0;f<a.length;f++){var g=a[f].start2+d,h=this.diff_text1(a[f].diffs),l=-1;if(h.length>this.Match_MaxBits){var k=this.match_main(b,h.substring(0,this.Match_MaxBits),g);-1!=k&&(l=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==l||k>=l)&&(k=-1)}else k=this.match_main(b,h,
g);if(-1==k)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=k-g,g=-1==l?b.substring(k,k+h.length):b.substring(k,l+this.Match_MaxBits),h==g)b=b.substring(0,k)+this.diff_text2(a[f].diffs)+b.substring(k+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);h=0;var m;for(l=0;l<a[f].diffs.length;l++){var p=a[f].diffs[l];p[0]!==DIFF_EQUAL&&(m=this.diff_xIndex(g,h));p[0]===
DIFF_INSERT?b=b.substring(0,k+m)+p[1]+b.substring(k+m):p[0]===DIFF_DELETE&&(b=b.substring(0,k+m)+b.substring(k+this.diff_xIndex(g,h+p[1].length)));p[0]!==DIFF_DELETE&&(h+=p[1].length)}}}b=b.substring(c.length,b.length-c.length);return[b,e]};
diff_match_patch.prototype.patch_addPadding=function(a){for(var b=this.Patch_Margin,c="",d=1;d<=b;d++)c+=String.fromCharCode(d);for(d=0;d<a.length;d++)a[d].start1+=b,a[d].start2+=b;d=a[0];var e=d.diffs;if(0==e.length||e[0][0]!=DIFF_EQUAL)e.unshift(new diff_match_patch.Diff(DIFF_EQUAL,c)),d.start1-=b,d.start2-=b,d.length1+=b,d.length2+=b;else if(b>e[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;
0==e.length||e[e.length-1][0]!=DIFF_EQUAL?(e.push(new diff_match_patch.Diff(DIFF_EQUAL,c)),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c<a.length;c++)if(!(a[c].length1<=b)){var d=a[c];a.splice(c--,1);for(var e=d.start1,f=d.start2,g="";0!==d.diffs.length;){var h=new diff_match_patch.patch_obj,l=!0;h.start1=e-g.length;h.start2=f-g.length;""!==g&&(h.length1=h.length2=g.length,h.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,g)));for(;0!==d.diffs.length&&h.length1<b-this.Patch_Margin;){g=d.diffs[0][0];var k=d.diffs[0][1];g===DIFF_INSERT?(h.length2+=
k.length,f+=k.length,h.diffs.push(d.diffs.shift()),l=!1):g===DIFF_DELETE&&1==h.diffs.length&&h.diffs[0][0]==DIFF_EQUAL&&k.length>2*b?(h.length1+=k.length,e+=k.length,l=!1,h.diffs.push(new diff_match_patch.Diff(g,k)),d.diffs.shift()):(k=k.substring(0,b-h.length1-this.Patch_Margin),h.length1+=k.length,e+=k.length,g===DIFF_EQUAL?(h.length2+=k.length,f+=k.length):l=!1,h.diffs.push(new diff_match_patch.Diff(g,k)),k==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(k.length))}g=this.diff_text2(h.diffs);
g=g.substring(g.length-this.Patch_Margin);k=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==k&&(h.length1+=k.length,h.length2+=k.length,0!==h.diffs.length&&h.diffs[h.diffs.length-1][0]===DIFF_EQUAL?h.diffs[h.diffs.length-1][1]+=k:h.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,k)));l||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b.join("")};
diff_match_patch.prototype.patch_fromText=function(a){var b=[];if(!a)return b;a=a.split("\n");for(var c=0,d=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;c<a.length;){var e=a[c].match(d);if(!e)throw Error("Invalid patch string: "+a[c]);var f=new diff_match_patch.patch_obj;b.push(f);f.start1=parseInt(e[1],10);""===e[2]?(f.start1--,f.length1=1):"0"==e[2]?f.length1=0:(f.start1--,f.length1=parseInt(e[2],10));f.start2=parseInt(e[3],10);""===e[4]?(f.start2--,f.length2=1):"0"==e[4]?f.length2=0:(f.start2--,f.length2=
parseInt(e[4],10));for(c++;c<a.length;){e=a[c].charAt(0);try{var g=decodeURI(a[c].substring(1))}catch(h){throw Error("Illegal escape in patch_fromText: "+g);}if("-"==e)f.diffs.push(new diff_match_patch.Diff(DIFF_DELETE,g));else if("+"==e)f.diffs.push(new diff_match_patch.Diff(DIFF_INSERT,g));else if(" "==e)f.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,g));else if("@"==e)break;else if(""!==e)throw Error('Invalid patch mode "'+e+'" in: '+g);c++}}return b};
diff_match_patch.patch_obj=function(){this.diffs=[];this.start2=this.start1=null;this.length2=this.length1=0};
diff_match_patch.patch_obj.prototype.toString=function(){for(var a=["@@ -"+(0===this.length1?this.start1+",0":1==this.length1?this.start1+1:this.start1+1+","+this.length1)+" +"+(0===this.length2?this.start2+",0":1==this.length2?this.start2+1:this.start2+1+","+this.length2)+" @@\n"],b,c=0;c<this.diffs.length;c++){switch(this.diffs[c][0]){case DIFF_INSERT:b="+";break;case DIFF_DELETE:b="-";break;case DIFF_EQUAL:b=" "}a[c+1]=b+encodeURI(this.diffs[c][1])+"\n"}return a.join("").replace(/%20/g," ")};
this.diff_match_patch=diff_match_patch;this.DIFF_DELETE=DIFF_DELETE;this.DIFF_INSERT=DIFF_INSERT;this.DIFF_EQUAL=DIFF_EQUAL;
@@ -1,119 +0,0 @@
.CodeMirror-merge {
position: relative;
border: 1px solid #ddd;
white-space: pre;
}
.CodeMirror-merge, .CodeMirror-merge .CodeMirror {
height: 350px;
}
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; }
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; }
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
.CodeMirror-merge-pane {
display: inline-block;
white-space: normal;
vertical-align: top;
}
.CodeMirror-merge-pane-rightmost {
position: absolute;
right: 0px;
z-index: 1;
}
.CodeMirror-merge-gap {
z-index: 2;
display: inline-block;
height: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
position: relative;
background: #f8f8f8;
}
.CodeMirror-merge-scrolllock-wrap {
position: absolute;
bottom: 0; left: 50%;
}
.CodeMirror-merge-scrolllock {
position: relative;
left: -50%;
cursor: pointer;
color: #555;
line-height: 1;
}
.CodeMirror-merge-scrolllock:after {
content: "\21db\00a0\00a0\21da";
}
.CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after {
content: "\21db\21da";
}
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
position: absolute;
left: 0; top: 0;
right: 0; bottom: 0;
line-height: 1;
}
.CodeMirror-merge-copy {
position: absolute;
cursor: pointer;
color: #44c;
z-index: 3;
}
.CodeMirror-merge-copy-reverse {
position: absolute;
cursor: pointer;
color: #44c;
}
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
background-position: bottom left;
background-repeat: repeat-x;
}
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
background-position: bottom left;
background-repeat: repeat-x;
}
.CodeMirror-merge-r-chunk { background: #ffffe0; }
.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; }
.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; }
.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; }
.CodeMirror-merge-l-chunk { background: #eef; }
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
.CodeMirror-merge-collapsed-widget:before {
content: "(...)";
}
.CodeMirror-merge-collapsed-widget {
cursor: pointer;
color: #88b;
background: #eef;
border: 1px solid #ddf;
font-size: 90%;
padding: 0 3px;
border-radius: 4px;
}
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }
File diff suppressed because it is too large. Load diff
@@ -1,128 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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.defineExtension("annotateScrollbar", function(options) {
if (typeof options == "string") options = {className: options};
return new Annotation(this, options);
});
CodeMirror.defineOption("scrollButtonHeight", 0);
function Annotation(cm, options) {
this.cm = cm;
this.options = options;
this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
this.annotations = [];
this.doRedraw = this.doUpdate = null;
this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
this.computeScale();
function scheduleRedraw(delay) {
clearTimeout(self.doRedraw);
self.doRedraw = setTimeout(function() { self.redraw(); }, delay);
}
var self = this;
cm.on("refresh", this.resizeHandler = function() {
clearTimeout(self.doUpdate);
self.doUpdate = setTimeout(function() {
if (self.computeScale()) scheduleRedraw(20);
}, 100);
});
cm.on("markerAdded", this.resizeHandler);
cm.on("markerCleared", this.resizeHandler);
if (options.listenForChanges !== false)
cm.on("changes", this.changeHandler = function() {
scheduleRedraw(250);
});
}
Annotation.prototype.computeScale = function() {
var cm = this.cm;
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
cm.getScrollerElement().scrollHeight
if (hScale != this.hScale) {
this.hScale = hScale;
return true;
}
};
Annotation.prototype.update = function(annotations) {
this.annotations = annotations;
this.redraw();
};
Annotation.prototype.redraw = function(compute) {
if (compute !== false) this.computeScale();
var cm = this.cm, hScale = this.hScale;
var frag = document.createDocumentFragment(), anns = this.annotations;
var wrapping = cm.getOption("lineWrapping");
var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
var curLine = null, curLineObj = null;
function getY(pos, top) {
if (curLine != pos.line) {
curLine = pos.line
curLineObj = cm.getLineHandle(pos.line)
var visual = cm.getLineHandleVisualStart(curLineObj)
if (visual != curLineObj) {
curLine = cm.getLineNumber(visual)
curLineObj = visual
}
}
if ((curLineObj.widgets && curLineObj.widgets.length) ||
(wrapping && curLineObj.height > singleLineH))
return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
var topY = cm.heightAtLine(curLineObj, "local");
return topY + (top ? 0 : curLineObj.height);
}
var lastLine = cm.lastLine()
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
var ann = anns[i];
if (ann.to.line > lastLine) continue;
var top = nextTop || getY(ann.from, true) * hScale;
var bottom = getY(ann.to, false) * hScale;
while (i < anns.length - 1) {
if (anns[i + 1].to.line > lastLine) break;
nextTop = getY(anns[i + 1].from, true) * hScale;
if (nextTop > bottom + .9) break;
ann = anns[++i];
bottom = getY(ann.to, false) * hScale;
}
if (bottom == top) continue;
var height = Math.max(bottom - top, 3);
var elt = frag.appendChild(document.createElement("div"));
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
+ (top + this.buttonHeight) + "px; height: " + height + "px";
elt.className = this.options.className;
if (ann.id) {
elt.setAttribute("annotation-id", ann.id);
}
}
this.div.textContent = "";
this.div.appendChild(frag);
};
Annotation.prototype.clear = function() {
this.cm.off("refresh", this.resizeHandler);
this.cm.off("markerAdded", this.resizeHandler);
this.cm.off("markerCleared", this.resizeHandler);
if (this.changeHandler) this.cm.off("changes", this.changeHandler);
this.div.parentNode.removeChild(this.div);
};
});
@@ -1,53 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Defines jumpToLine command. Uses dialog.js if present.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../dialog/dialog"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
// default search panel location
CodeMirror.defineOption("search", {bottom: false});
function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom});
else f(prompt(shortText, deflt));
}
function getJumpDialog(cm) {
return cm.phrase("Jump to line:") + ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">' + cm.phrase("(Use line:column or scroll% syntax)") + '</span>';
}
function interpretLine(cm, string) {
var num = Number(string)
if (/^[-+]/.test(string)) return cm.getCursor().line + num
else return num - 1
}
CodeMirror.commands.jumpToLine = function(cm) {
var cur = cm.getCursor();
dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) {
if (!posStr) return;
var match;
if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
} else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
cm.setCursor(line - 1, cur.ch);
} else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), cur.ch);
}
});
};
CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
});
@@ -1,167 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Highlighting text that matches the selection
//
// Defines an option highlightSelectionMatches, which, when enabled,
// will style strings that match the selection throughout the
// document.
//
// The option can be set to true to simply enable it, or to a
// {minChars, style, wordsOnly, showToken, delay} object to explicitly
// configure it. minChars is the minimum amount of characters that should be
// selected for the behavior to occur, and style is the token style to
// apply to the matches. This will be prefixed by "cm-" to create an
// actual CSS class name. If wordsOnly is enabled, the matches will be
// highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before
// highlighting the matches. If annotateScrollbar is enabled, the occurrences
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var defaults = {
style: "matchhighlight",
minChars: 2,
delay: 100,
wordsOnly: false,
annotateScrollbar: false,
showToken: false,
trim: true
}
function State(options) {
this.options = {}
for (var name in defaults)
this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.overlay = this.timeout = null;
this.matchesonscroll = null;
this.active = false;
}
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
removeOverlay(cm);
clearTimeout(cm.state.matchHighlighter.timeout);
cm.state.matchHighlighter = null;
cm.off("cursorActivity", cursorActivity);
cm.off("focus", onFocus)
}
if (val) {
var state = cm.state.matchHighlighter = new State(val);
if (cm.hasFocus()) {
state.active = true
highlightMatches(cm)
} else {
cm.on("focus", onFocus)
}
cm.on("cursorActivity", cursorActivity);
}
});
function cursorActivity(cm) {
var state = cm.state.matchHighlighter;
if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
}
function onFocus(cm) {
var state = cm.state.matchHighlighter
if (!state.active) {
state.active = true
scheduleHighlight(cm, state)
}
}
function scheduleHighlight(cm, state) {
clearTimeout(state.timeout);
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
}
function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp((/\w/.test(query.charAt(0)) ? "\\b" : "") +
query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") +
(/\w/.test(query.charAt(query.length - 1)) ? "\\b" : "")) : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
{className: "CodeMirror-selection-highlight-scrollbar"});
}
}
function removeOverlay(cm) {
var state = cm.state.matchHighlighter;
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
if (state.matchesonscroll) {
state.matchesonscroll.clear();
state.matchesonscroll = null;
}
}
}
function highlightMatches(cm) {
cm.operation(function() {
var state = cm.state.matchHighlighter;
removeOverlay(cm);
if (!cm.somethingSelected() && state.options.showToken) {
var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end)
addOverlay(cm, line.slice(start, end), re, state.options.style);
return;
}
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return;
if (state.options.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to)
if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
if (selection.length >= state.options.minChars)
addOverlay(cm, selection, false, state.options.style);
});
}
function isWord(cm, from, to) {
var str = cm.getRange(from, to);
if (str.match(/^\w+$/) !== null) {
if (from.ch > 0) {
var pos = {line: from.line, ch: from.ch - 1};
var chr = cm.getRange(pos, from);
if (chr.match(/\W/) === null) return false;
}
if (to.ch < cm.getLine(from.line).length) {
var pos = {line: to.line, ch: to.ch + 1};
var chr = cm.getRange(to, pos);
if (chr.match(/\W/) === null) return false;
}
return true;
} else return false;
}
function boundariesAround(stream, re) {
return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
(stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
}
function makeOverlay(query, hasBoundary, style) {
return {token: function(stream) {
if (stream.match(query) &&
(!hasBoundary || boundariesAround(stream, hasBoundary)))
return style;
stream.next();
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
}};
}
});
@@ -1,8 +0,0 @@
.CodeMirror-search-match {
background: gold;
border-top: 1px solid orange;
border-bottom: 1px solid orange;
-moz-box-sizing: border-box;
box-sizing: border-box;
opacity: .5;
}
@@ -1,97 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
if (typeof options == "string") options = {className: options};
if (!options) options = {};
return new SearchAnnotation(this, query, caseFold, options);
});
function SearchAnnotation(cm, query, caseFold, options) {
this.cm = cm;
this.options = options;
var annotateOptions = {listenForChanges: false};
for (var prop in options) annotateOptions[prop] = options[prop];
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
this.annotation = cm.annotateScrollbar(annotateOptions);
this.query = query;
this.caseFold = caseFold;
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
this.matches = [];
this.update = null;
this.findMatches();
this.annotation.update(this.matches);
var self = this;
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
}
var MAX_MATCHES = 1000;
SearchAnnotation.prototype.findMatches = function() {
if (!this.gap) return;
for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
if (match.from.line >= this.gap.to) break;
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
}
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline});
var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
while (cursor.findNext()) {
var match = {from: cursor.from(), to: cursor.to()};
if (match.from.line >= this.gap.to) break;
this.matches.splice(i++, 0, match);
if (this.matches.length > maxMatches) break;
}
this.gap = null;
};
function offsetLine(line, changeStart, sizeChange) {
if (line <= changeStart) return line;
return Math.max(changeStart, line + sizeChange);
}
SearchAnnotation.prototype.onChange = function(change) {
var startLine = change.from.line;
var endLine = CodeMirror.changeEnd(change).line;
var sizeChange = endLine - change.to.line;
if (this.gap) {
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
} else {
this.gap = {from: change.from.line, to: endLine + 1};
}
if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
var newFrom = offsetLine(match.from.line, startLine, sizeChange);
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
var newTo = offsetLine(match.to.line, startLine, sizeChange);
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
}
clearTimeout(this.update);
var self = this;
this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
};
SearchAnnotation.prototype.updateAfterChange = function() {
this.findMatches();
this.annotation.update(this.matches);
};
SearchAnnotation.prototype.clear = function() {
this.cm.off("change", this.changeHandler);
this.annotation.clear();
};
});
@@ -1,295 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.
// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
// default search panel location
CodeMirror.defineOption("search", {bottom: false});
function searchOverlay(query, caseInsensitive) {
if (typeof query == "string")
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
else if (!query.global)
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
return {token: function(stream) {
query.lastIndex = stream.pos;
var match = query.exec(stream.string);
if (match && match.index == stream.pos) {
stream.pos += match[0].length || 1;
return "searching";
} else if (match) {
stream.pos = match.index;
} else {
stream.skipToEnd();
}
}};
}
function SearchState() {
this.posFrom = this.posTo = this.lastQuery = this.query = null;
this.overlay = null;
}
function getSearchState(cm) {
return cm.state.search || (cm.state.search = new SearchState());
}
function queryCaseInsensitive(query) {
return typeof query == "string" && query == query.toLowerCase();
}
function getSearchCursor(cm, query, pos) {
// Heuristic: if the query string is all lowercase, do a case insensitive search.
return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
}
function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
cm.openDialog(text, onEnter, {
value: deflt,
selectValueOnOpen: true,
closeOnEnter: false,
onClose: function() { clearSearch(cm); },
onKeyDown: onKeyDown,
bottom: cm.options.search.bottom
});
}
function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom});
else f(prompt(shortText, deflt));
}
function confirmDialog(cm, text, shortText, fs) {
if (cm.openConfirm) cm.openConfirm(text, fs);
else if (confirm(shortText)) fs[0]();
}
function parseString(string) {
return string.replace(/\\([nrt\\])/g, function(match, ch) {
if (ch == "n") return "\n"
if (ch == "r") return "\r"
if (ch == "t") return "\t"
if (ch == "\\") return "\\"
return match
})
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
if (isRE) {
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
catch(e) {} // Not a regular expression after all, do a string search
} else {
query = parseString(query)
}
if (typeof query == "string" ? query == "" : query.test(""))
query = /x^/;
return query;
}
function startSearch(cm, state, query) {
state.queryText = query;
state.query = parseQuery(query);
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
cm.addOverlay(state.overlay);
if (cm.showMatchesOnScrollbar) {
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
}
}
function doSearch(cm, rev, persistent, immediate) {
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery;
if (q instanceof RegExp && q.source == "x^") q = null
if (persistent && cm.openDialog) {
var hiding = null
var searchNext = function(query, event) {
CodeMirror.e_stop(event);
if (!query) return;
if (query != state.queryText) {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor();
}
if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) {
var dialog
if (to.line < 3 && document.querySelector &&
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4
})
};
persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) {
var keyName = CodeMirror.keyName(event)
var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
if (cmd == "findNext" || cmd == "findPrev" ||
cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
CodeMirror.e_stop(event);
startSearch(cm, getSearchState(cm), query);
cm.execCommand(cmd);
} else if (cmd == "find" || cmd == "findPersistent") {
CodeMirror.e_stop(event);
searchNext(query, event);
}
});
if (immediate && q) {
startSearch(cm, state, q);
findNext(cm, rev);
}
} else {
dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) {
if (query && !state.query) cm.operation(function() {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor();
findNext(cm, rev);
});
});
}
}
function findNext(cm, rev, callback) {cm.operation(function() {
var state = getSearchState(cm);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) {
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
if (!cursor.find(rev)) return;
}
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
state.posFrom = cursor.from(); state.posTo = cursor.to();
if (callback) callback(cursor.from(), cursor.to())
});}
function clearSearch(cm) {cm.operation(function() {
var state = getSearchState(cm);
state.lastQuery = state.query;
if (!state.query) return;
state.query = state.queryText = null;
cm.removeOverlay(state.overlay);
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
});}
function el(tag, attrs) {
var element = tag ? document.createElement(tag) : document.createDocumentFragment();
for (var key in attrs) {
element[key] = attrs[key];
}
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i]
element.appendChild(typeof child == "string" ? document.createTextNode(child) : child);
}
return element;
}
function getQueryDialog(cm) {
var label = el("label", {className: "CodeMirror-search-label"},
cm.phrase("Search:"),
el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field",
id: "CodeMirror-search-field"}));
label.setAttribute("for","CodeMirror-search-field");
return el("", null, label, " ",
el("span", {style: "color: #666", className: "CodeMirror-search-hint"},
cm.phrase("(Use /re/ syntax for regexp search)")));
}
function getReplaceQueryDialog(cm) {
return el("", null, " ",
el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ",
el("span", {style: "color: #666", className: "CodeMirror-search-hint"},
cm.phrase("(Use /re/ syntax for regexp search)")));
}
function getReplacementQueryDialog(cm) {
return el("", null,
el("span", {className: "CodeMirror-search-label"}, cm.phrase("With:")), " ",
el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}));
}
function getDoReplaceConfirm(cm) {
return el("", null,
el("span", {className: "CodeMirror-search-label"}, cm.phrase("Replace?")), " ",
el("button", {}, cm.phrase("Yes")), " ",
el("button", {}, cm.phrase("No")), " ",
el("button", {}, cm.phrase("All")), " ",
el("button", {}, cm.phrase("Stop")));
}
function replaceAll(cm, query, text) {
cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") {
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
} else cursor.replace(text);
}
});
}
function replace(cm, all) {
if (cm.getOption("readOnly")) return;
var query = cm.getSelection() || getSearchState(cm).lastQuery;
var dialogText = all ? cm.phrase("Replace all:") : cm.phrase("Replace:")
var fragment = el("", null,
el("span", {className: "CodeMirror-search-label"}, dialogText),
getReplaceQueryDialog(cm))
dialog(cm, fragment, dialogText, query, function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) {
text = parseString(text)
if (all) {
replaceAll(cm, query, text)
} else {
clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
var advance = function() {
var start = cursor.from(), match;
if (!(match = cursor.findNext())) {
cursor = getSearchCursor(cm, query);
if (!(match = cursor.findNext()) ||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
}
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"),
[function() {doReplace(match);}, advance,
function() {replaceAll(cm, query, text)}]);
};
var doReplace = function(match) {
cursor.replace(typeof query == "string" ? text :
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
advance();
};
advance();
}
});
});
}
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
CodeMirror.commands.clearSearch = clearSearch;
CodeMirror.commands.replace = replace;
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
});
@@ -1,305 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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"
var Pos = CodeMirror.Pos
function regexpFlags(regexp) {
var flags = regexp.flags
return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
+ (regexp.global ? "g" : "")
+ (regexp.multiline ? "m" : "")
}
function ensureFlags(regexp, flags) {
var current = regexpFlags(regexp), target = current
for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
target += flags.charAt(i)
return current == target ? regexp : new RegExp(regexp.source, target)
}
function maybeMultiline(regexp) {
return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
}
function searchRegexpForward(doc, regexp, start) {
regexp = ensureFlags(regexp, "g")
for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
regexp.lastIndex = ch
var string = doc.getLine(line), match = regexp.exec(string)
if (match)
return {from: Pos(line, match.index),
to: Pos(line, match.index + match[0].length),
match: match}
}
}
function searchRegexpForwardMultiline(doc, regexp, start) {
if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
regexp = ensureFlags(regexp, "gm")
var string, chunk = 1
for (var line = start.line, last = doc.lastLine(); line <= last;) {
// This grows the search buffer in exponentially-sized chunks
// between matches, so that nearby matches are fast and don't
// require concatenating the whole document (in case we're
// searching for something that has tons of matches), but at the
// same time, the amount of retries is limited.
for (var i = 0; i < chunk; i++) {
if (line > last) break
var curLine = doc.getLine(line++)
string = string == null ? curLine : string + "\n" + curLine
}
chunk = chunk * 2
regexp.lastIndex = start.ch
var match = regexp.exec(string)
if (match) {
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length
return {from: Pos(startLine, startCh),
to: Pos(startLine + inside.length - 1,
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
match: match}
}
}
}
function lastMatchIn(string, regexp, endMargin) {
var match, from = 0
while (from <= string.length) {
regexp.lastIndex = from
var newMatch = regexp.exec(string)
if (!newMatch) break
var end = newMatch.index + newMatch[0].length
if (end > string.length - endMargin) break
if (!match || end > match.index + match[0].length)
match = newMatch
from = newMatch.index + 1
}
return match
}
function searchRegexpBackward(doc, regexp, start) {
regexp = ensureFlags(regexp, "g")
for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
var string = doc.getLine(line)
var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch)
if (match)
return {from: Pos(line, match.index),
to: Pos(line, match.index + match[0].length),
match: match}
}
}
function searchRegexpBackwardMultiline(doc, regexp, start) {
if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start)
regexp = ensureFlags(regexp, "gm")
var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch
for (var line = start.line, first = doc.firstLine(); line >= first;) {
for (var i = 0; i < chunkSize && line >= first; i++) {
var curLine = doc.getLine(line--)
string = string == null ? curLine : curLine + "\n" + string
}
chunkSize *= 2
var match = lastMatchIn(string, regexp, endMargin)
if (match) {
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
var startLine = line + before.length, startCh = before[before.length - 1].length
return {from: Pos(startLine, startCh),
to: Pos(startLine + inside.length - 1,
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
match: match}
}
}
}
var doFold, noFold
if (String.prototype.normalize) {
doFold = function(str) { return str.normalize("NFD").toLowerCase() }
noFold = function(str) { return str.normalize("NFD") }
} else {
doFold = function(str) { return str.toLowerCase() }
noFold = function(str) { return str }
}
// Maps a position in a case-folded line back to a position in the original line
// (compensating for codepoints increasing in number during folding)
function adjustPos(orig, folded, pos, foldFunc) {
if (orig.length == folded.length) return pos
for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) {
if (min == max) return min
var mid = (min + max) >> 1
var len = foldFunc(orig.slice(0, mid)).length
if (len == pos) return mid
else if (len > pos) max = mid
else min = mid + 1
}
}
function searchStringForward(doc, query, start, caseFold) {
// Empty string would match anything and never progress, so we
// define it to match nothing instead.
if (!query.length) return null
var fold = caseFold ? doFold : noFold
var lines = fold(query).split(/\r|\n\r?/)
search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) {
var orig = doc.getLine(line).slice(ch), string = fold(orig)
if (lines.length == 1) {
var found = string.indexOf(lines[0])
if (found == -1) continue search
var start = adjustPos(orig, string, found, fold) + ch
return {from: Pos(line, adjustPos(orig, string, found, fold) + ch),
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)}
} else {
var cutFrom = string.length - lines[0].length
if (string.slice(cutFrom) != lines[0]) continue search
for (var i = 1; i < lines.length - 1; i++)
if (fold(doc.getLine(line + i)) != lines[i]) continue search
var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1]
if (endString.slice(0, lastLine.length) != lastLine) continue search
return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch),
to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))}
}
}
}
function searchStringBackward(doc, query, start, caseFold) {
if (!query.length) return null
var fold = caseFold ? doFold : noFold
var lines = fold(query).split(/\r|\n\r?/)
search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) {
var orig = doc.getLine(line)
if (ch > -1) orig = orig.slice(0, ch)
var string = fold(orig)
if (lines.length == 1) {
var found = string.lastIndexOf(lines[0])
if (found == -1) continue search
return {from: Pos(line, adjustPos(orig, string, found, fold)),
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))}
} else {
var lastLine = lines[lines.length - 1]
if (string.slice(0, lastLine.length) != lastLine) continue search
for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++)
if (fold(doc.getLine(start + i)) != lines[i]) continue search
var top = doc.getLine(line + 1 - lines.length), topString = fold(top)
if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search
return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)),
to: Pos(line, adjustPos(orig, string, lastLine.length, fold))}
}
}
}
function SearchCursor(doc, query, pos, options) {
this.atOccurrence = false
this.afterEmptyMatch = false
this.doc = doc
pos = pos ? doc.clipPos(pos) : Pos(0, 0)
this.pos = {from: pos, to: pos}
var caseFold
if (typeof options == "object") {
caseFold = options.caseFold
} else { // Backwards compat for when caseFold was the 4th argument
caseFold = options
options = null
}
if (typeof query == "string") {
if (caseFold == null) caseFold = false
this.matches = function(reverse, pos) {
return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
}
} else {
query = ensureFlags(query, "gm")
if (!options || options.multiline !== false)
this.matches = function(reverse, pos) {
return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
}
else
this.matches = function(reverse, pos) {
return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
}
}
}
SearchCursor.prototype = {
findNext: function() {return this.find(false)},
findPrevious: function() {return this.find(true)},
find: function(reverse) {
var head = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
if (this.afterEmptyMatch && this.atOccurrence) {
// do not return the same 0 width match twice
head = Pos(head.line, head.ch)
if (reverse) {
head.ch--;
if (head.ch < 0) {
head.line--;
head.ch = (this.doc.getLine(head.line) || "").length;
}
} else {
head.ch++;
if (head.ch > (this.doc.getLine(head.line) || "").length) {
head.ch = 0;
head.line++;
}
}
if (CodeMirror.cmpPos(head, this.doc.clipPos(head)) != 0) {
return this.atOccurrence = false
}
}
var result = this.matches(reverse, head)
this.afterEmptyMatch = result && CodeMirror.cmpPos(result.from, result.to) == 0
if (result) {
this.pos = result
this.atOccurrence = true
return this.pos.match || true
} else {
var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0)
this.pos = {from: end, to: end}
return this.atOccurrence = false
}
},
from: function() {if (this.atOccurrence) return this.pos.from},
to: function() {if (this.atOccurrence) return this.pos.to},
replace: function(newText, origin) {
if (!this.atOccurrence) return
var lines = CodeMirror.splitLines(newText)
this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin)
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0))
}
}
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this.doc, query, pos, caseFold)
})
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this, query, pos, caseFold)
})
CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
var ranges = []
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold)
while (cur.findNext()) {
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break
ranges.push({anchor: cur.from(), head: cur.to()})
}
if (ranges.length)
this.setSelections(ranges, 0)
})
});
@@ -1,72 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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";
var WRAP_CLASS = "CodeMirror-activeline";
var BACK_CLASS = "CodeMirror-activeline-background";
var GUTT_CLASS = "CodeMirror-activeline-gutter";
CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
var prev = old == CodeMirror.Init ? false : old;
if (val == prev) return
if (prev) {
cm.off("beforeSelectionChange", selectionChange);
clearActiveLines(cm);
delete cm.state.activeLines;
}
if (val) {
cm.state.activeLines = [];
updateActiveLines(cm, cm.listSelections());
cm.on("beforeSelectionChange", selectionChange);
}
});
function clearActiveLines(cm) {
for (var i = 0; i < cm.state.activeLines.length; i++) {
cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS);
}
}
function sameArray(a, b) {
if (a.length != b.length) return false;
for (var i = 0; i < a.length; i++)
if (a[i] != b[i]) return false;
return true;
}
function updateActiveLines(cm, ranges) {
var active = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
var option = cm.getOption("styleActiveLine");
if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty())
continue
var line = cm.getLineHandleVisualStart(range.head.line);
if (active[active.length - 1] != line) active.push(line);
}
if (sameArray(cm.state.activeLines, active)) return;
cm.operation(function() {
clearActiveLines(cm);
for (var i = 0; i < active.length; i++) {
cm.addLineClass(active[i], "wrap", WRAP_CLASS);
cm.addLineClass(active[i], "background", BACK_CLASS);
cm.addLineClass(active[i], "gutter", GUTT_CLASS);
}
cm.state.activeLines = active;
});
}
function selectionChange(cm, sel) {
updateActiveLines(cm, sel.ranges);
}
});
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,875 @@
var CM6=(()=>{var _k=Object.create;var es=Object.defineProperty;var Zk=Object.getOwnPropertyDescriptor;var Dk=Object.getOwnPropertyNames;var Ik=Object.getPrototypeOf,Bk=Object.prototype.hasOwnProperty;var Nk=(t,e,i)=>e in t?es(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i;var jk=(t,e)=>()=>{try{return e||t((e={exports:{}}).exports,e),e.exports}catch(i){throw e=0,i}},zk=(t,e)=>{for(var i in e)es(t,i,{get:e[i],enumerable:!0})},gg=(t,e,i,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Dk(e))!Bk.call(t,r)&&r!==i&&es(t,r,{get:()=>e[r],enumerable:!(n=Zk(e,r))||n.enumerable});return t};var Yk=(t,e,i)=>(i=t!=null?_k(Ik(t)):{},gg(e||!t||!t.__esModule?es(i,"default",{value:t,enumerable:!0}):i,t)),qk=t=>gg(es({},"__esModule",{value:!0}),t);var J=(t,e,i)=>Nk(t,typeof e!="symbol"?e+"":e,i);var xk=jk((CZ,Sk)=>{function ak(t){return t instanceof Map?t.clear=t.delete=t.set=function(){throw new Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=function(){throw new Error("set is read-only")}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach(e=>{let i=t[e],n=typeof i;(n==="object"||n==="function")&&!Object.isFrozen(i)&&ak(i)}),t}var sc=class{constructor(e){e.data===void 0&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}};function ck(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")}function on(t,...e){let i=Object.create(null);for(let n in t)i[n]=t[n];return e.forEach(function(n){for(let r in n)i[r]=n[r]}),i}var yL="</span>",ik=t=>!!t.scope,SL=(t,{prefix:e})=>{if(t.startsWith("language:"))return t.replace("language:","language-");if(t.includes(".")){let i=t.split(".");return[`${e}${i.shift()}`,...i.map((n,r)=>`${n}${"_".repeat(r+1)}`)].join(" ")}return`${e}${t}`},tg=class{constructor(e,i){this.buffer="",this.classPrefix=i.classPrefix,e.walk(this)}addText(e){this.buffer+=ck(e)}openNode(e){if(!ik(e))return;let i=SL(e.scope,{prefix:this.classPrefix});this.span(i)}closeNode(e){ik(e)&&(this.buffer+=yL)}value(){return this.buffer}span(e){this.buffer+=`<span class="${e}">`}},nk=(t={})=>{let e={children:[]};return Object.assign(e,t),e},ig=class t{constructor(){this.rootNode=nk(),this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){let i=nk({scope:e});this.add(i),this.stack.push(i)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,i){return typeof i=="string"?e.addText(i):i.children&&(e.openNode(i),i.children.forEach(n=>this._walk(e,n)),e.closeNode(i)),e}static _collapse(e){typeof e!="string"&&e.children&&(e.children.every(i=>typeof i=="string")?e.children=[e.children.join("")]:e.children.forEach(i=>{t._collapse(i)}))}},ng=class extends ig{constructor(e){super(),this.options=e}addText(e){e!==""&&this.add(e)}startScope(e){this.openNode(e)}endScope(){this.closeNode()}__addSublanguage(e,i){let n=e.root;i&&(n.scope=`language:${i}`),this.add(n)}toHTML(){return new tg(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}};function vo(t){return t?typeof t=="string"?t:t.source:null}function hk(t){return Kn("(?=",t,")")}function xL(t){return Kn("(?:",t,")*")}function kL(t){return Kn("(?:",t,")?")}function Kn(...t){return t.map(i=>vo(i)).join("")}function wL(t){let e=t[t.length-1];return typeof e=="object"&&e.constructor===Object?(t.splice(t.length-1,1),e):{}}function sg(...t){return"("+(wL(t).capture?"":"?:")+t.map(n=>vo(n)).join("|")+")"}function fk(t){return new RegExp(t.toString()+"|").exec("").length-1}function vL(t,e){let i=t&&t.exec(e);return i&&i.index===0}var QL=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function og(t,{joinWith:e}){let i=0;return t.map(n=>{i+=1;let r=i,s=vo(n),o="";for(;s.length>0;){let l=QL.exec(s);if(!l){o+=s;break}o+=s.substring(0,l.index),s=s.substring(l.index+l[0].length),l[0][0]==="\\"&&l[1]?o+="\\"+String(Number(l[1])+r):(o+=l[0],l[0]==="("&&i++)}return o}).map(n=>`(${n})`).join(e)}var PL=/\b\B/,uk="[a-zA-Z]\\w*",lg="[a-zA-Z_]\\w*",dk="\\b\\d+(\\.\\d+)?",pk="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",gk="\\b(0b[01]+)",$L="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",TL=(t={})=>{let e=/^#![ ]*\//;return t.binary&&(t.begin=Kn(e,/.*\b/,t.binary,/\b.*/)),on({scope:"meta",begin:e,end:/$/,relevance:0,"on:begin":(i,n)=>{i.index!==0&&n.ignoreMatch()}},t)},Qo={begin:"\\\\[\\s\\S]",relevance:0},CL={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[Qo]},AL={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[Qo]},RL={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|suLine truncated
https://github.com/highlightjs/highlight.js/issues/2277`),K=P,V=X),W===void 0&&(W=!0);let le={code:V,language:K};B("before:highlight",le);let ie=le.result?le.result:f(le.language,le.code,W);return ie.code=le.code,B("after:highlight",ie),ie}function f(P,X,W,V){let K=Object.create(null);function le(D,Y){return D.keywords[Y]}function ie(){if(!H.keywords){Ye.addText(Qe);return}let D=0;H.keywordPatternRe.lastIndex=0;let Y=H.keywordPatternRe.exec(Qe),ee="";for(;Y;){ee+=Qe.substring(D,Y.index);let ye=ti.case_insensitive?Y[0].toLowerCase():Y[0],Fe=le(H,ye);if(Fe){let[bi,Lk]=Fe;if(Ye.addText(ee),ee="",K[ye]=(K[ye]||0)+1,K[ye]<=lX&&($o+=Lk),bi.startsWith("_"))ee+=Y[0];else{let Xk=ti.classNameAliases[bi]||bi;Ae(Y[0],Xk)}}else ee+=Y[0];D=H.keywordPatternRe.lastIndex,Y=H.keywordPatternRe.exec(Qe)}ee+=Qe.substring(D),Ye.addText(ee)}function me(){if(Qe==="")return;let D=null;if(typeof H.subLanguage=="string"){if(!e[H.subLanguage]){Ye.addText(Qe);return}D=f(H.subLanguage,Qe,!0,pg[H.subLanguage]),pg[H.subLanguage]=D._top}else D=d(Qe,H.subLanguage.length?H.subLanguage:null);H.relevance>0&&($o+=D.relevance),Ye.__addSublanguage(D._emitter,D.language)}function be(){H.subLanguage!=null?me():ie(),Qe=""}function Ae(D,Y){D!==""&&(Ye.startScope(Y),Ye.addText(D),Ye.endScope())}function Ct(D,Y){let ee=1,ye=Y.length-1;for(;ee<=ye;){if(!D._emit[ee]){ee++;continue}let Fe=ti.classNameAliases[D[ee]]||D[ee],bi=Y[ee];Fe?Ae(bi,Fe):(Qe=bi,ie(),Qe=""),ee++}}function Mi(D,Y){return D.scope&&typeof D.scope=="string"&&Ye.openNode(ti.classNameAliases[D.scope]||D.scope),D.beginScope&&(D.beginScope._wrap?(Ae(Qe,ti.classNameAliases[D.beginScope._wrap]||D.beginScope._wrap),Qe=""):D.beginScope._multi&&(Ct(D.beginScope,Y),Qe="")),H=Object.create(D,{parent:{value:H}}),H}function ug(D,Y,ee){let ye=vL(D.endRe,ee);if(ye){if(D["on:end"]){let Fe=new sc(D);D["on:end"](Y,Fe),Fe.isMatchIgnored&&(ye=!1)}if(ye){for(;D.endsParent&&D.parent;)D=D.parent;return D}}if(D.endsWithParent)return ug(D.parent,Y,ee)}function Ck(D){return H.matcher.regexIndex===0?(Qe+=D[0],1):(dc=!0,0)}function Ak(D){let Y=D[0],ee=D.rule,ye=new sc(ee),Fe=[ee.__beforeBegin,ee["on:begin"]];for(let bi of Fe)if(bi&&(bi(D,ye),ye.isMatchIgnored))return Ck(Y);return ee.skip?Qe+=Y:(ee.excludeBegin&&(Qe+=Y),be(),!ee.returnBegin&&!ee.excludeBegin&&(Qe=Y)),Mi(ee,D),ee.returnBegin?0:Y.length}function Rk(D){let Y=D[0],ee=X.substring(D.index),ye=ug(H,D,ee);if(!ye)return lk;let Fe=H;H.endScope&&H.endScope._wrap?(be(),Ae(Y,H.endScope._wrap)):H.endScope&&H.endScope._multi?(be(),Ct(H.endScope,D)):Fe.skip?Qe+=Y:(Fe.returnEnd||Fe.excludeEnd||(Qe+=Y),be(),Fe.excludeEnd&&(Qe=Y));do H.scope&&Ye.closeNode(),!H.skip&&!H.subLanguage&&($o+=H.relevance),H=H.parent;while(H!==ye.parent);return ye.starts&&Mi(ye.starts,D),Fe.returnEnd?0:Y.length}function Ek(){let D=[];for(let Y=H;Y!==ti;Y=Y.parent)Y.scope&&D.unshift(Y.scope);D.forEach(Y=>Ye.openNode(Y))}let Po={};function dg(D,Y){let ee=Y&&Y[0];if(Qe+=D,ee==null)return be(),0;if(Po.type==="begin"&&Y.type==="end"&&Po.index===Y.index&&ee===""){if(Qe+=X.slice(Y.index,Y.index+1),!r){let ye=new Error(`0 width match regex (${P})`);throw ye.languageName=P,ye.badRule=Po.rule,ye}return 1}if(Po=Y,Y.type==="begin")return Ak(Y);if(Y.type==="illegal"&&!W){let ye=new Error('Illegal lexeme "'+ee+'" for mode "'+(H.scope||"<unnamed>")+'"');throw ye.mode=H,ye}else if(Y.type==="end"){let ye=Rk(Y);if(ye!==lk)return ye}if(Y.type==="illegal"&&ee==="")return Qe+=`
`,1;if(uc>1e5&&uc>Y.index*3)throw new Error("potential infinite loop, way more iterations than matches");return Qe+=ee,ee.length}let ti=L(P);if(!ti)throw Hn(s.replace("{}",P)),new Error('Unknown language: "'+P+'"');let Mk=rX(ti),fc="",H=V||Mk,pg={},Ye=new l.__emitter(l);Ek();let Qe="",$o=0,ln=0,uc=0,dc=!1;try{if(ti.__emitTokens)ti.__emitTokens(X,Ye);else{for(H.matcher.considerAll();;){uc++,dc?dc=!1:H.matcher.considerAll(),H.matcher.lastIndex=ln;let D=H.matcher.exec(X);if(!D)break;let Y=X.substring(ln,D.index),ee=dg(Y,D);ln=D.index+ee}dg(X.substring(ln))}return Ye.finalize(),fc=Ye.toHTML(),{language:P,value:fc,relevance:$o,illegal:!1,_emitter:Ye,_top:H}}catch(D){if(D.message&&D.message.includes("Illegal"))return{language:P,value:eg(X),illegal:!0,relevance:0,_illegalBy:{message:D.message,index:ln,context:X.slice(ln-100,ln+100),mode:D.mode,resultSoFar:fc},_emitter:Ye};if(r)return{language:P,value:eg(X),illegal:!1,relevance:0,errorRaised:D,_emitter:Ye,_top:H};throw D}}function u(P){let X={value:eg(P),illegal:!1,relevance:0,_top:o,_emitter:new l.__emitter(l)};return X._emitter.addText(P),X}function d(P,X){X=X||l.languages||Object.keys(e);let W=u(P),V=X.filter(L).filter(z).map(be=>f(be,P,!1));V.unshift(W);let K=V.sort((be,Ae)=>{if(be.relevance!==Ae.relevance)return Ae.relevance-be.relevance;if(be.language&&Ae.language){if(L(be.language).supersetOf===Ae.language)return 1;if(L(Ae.language).supersetOf===be.language)return-1}return 0}),[le,ie]=K,me=le;return me.secondBest=ie,me}function p(P,X,W){let V=X&&i[X]||W;P.classList.add("hljs"),P.classList.add(`language-${V}`)}function g(P){let X=null,W=h(P);if(a(W))return;if(B("before:highlightElement",{el:P,language:W}),P.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",P);return}if(P.children.length>0&&(l.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(P)),l.throwUnescapedHTML))throw new rg("One of your code blocks includes unescaped HTML.",P.innerHTML);X=P;let V=X.textContent,K=W?c(V,{language:W,ignoreIllegals:!0}):d(V);P.innerHTML=K.value,P.dataset.highlighted="yes",p(P,W,K.language),P.result={language:K.language,re:K.relevance,relevance:K.relevance},K.secondBest&&(P.secondBest={language:K.secondBest.language,relevance:K.secondBest.relevance}),B("after:highlightElement",{el:P,result:K,text:V})}function m(P){l=ok(l,P)}let b=()=>{Q(),Kr("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function y(){Q(),Kr("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let x=!1;function Q(){function P(){Q()}if(document.readyState==="loading"){x||window.addEventListener("DOMContentLoaded",P,!1),x=!0;return}document.querySelectorAll(l.cssSelector).forEach(g)}function S(P,X){let W=null;try{W=X(t)}catch(V){if(Hn("Language definition for '{}' could not be registered.".replace("{}",P)),r)Hn(V);else throw V;W=o}W.name||(W.name=P),e[P]=W,W.rawDefinition=X.bind(null,t),W.aliases&&I(W.aliases,{languageName:P})}function k(P){delete e[P];for(let X of Object.keys(i))i[X]===P&&delete i[X]}function w(){return Object.keys(e)}function L(P){return P=(P||"").toLowerCase(),e[P]||e[i[P]]}function I(P,{languageName:X}){typeof P=="string"&&(P=[P]),P.forEach(W=>{i[W.toLowerCase()]=X})}function z(P){let X=L(P);return X&&!X.disableAutodetect}function _(P){P["before:highlightBlock"]&&!P["before:highlightElement"]&&(P["before:highlightElement"]=X=>{P["before:highlightBlock"](Object.assign({block:X.el},X))}),P["after:highlightBlock"]&&!P["after:highlightElement"]&&(P["after:highlightElement"]=X=>{P["after:highlightBlock"](Object.assign({block:X.el},X))})}function $(P){_(P),n.push(P)}function N(P){let X=n.indexOf(P);X!==-1&&n.splice(X,1)}function B(P,X){let W=P;n.forEach(function(V){V[W]&&V[W](X)})}function U(P){return Kr("10.7.0","highlightBlock will be removed entirely in v12.0"),Kr("10.7.0","Please use highlightElement now."),g(P)}Object.assign(t,{highlight:c,highlightAuto:d,highlightAll:Q,highlightElement:g,highlightBlock:U,configure:m,initHighlighting:b,initHighlightingOnLoad:y,registerLanguage:S,unregisterLanguage:k,listLanguages:w,getLanguage:L,registerAliases:I,autoDetection:z,inherit:ok,addPlugin:$,removePlugin:N}),t.debugMode=function(){r=!1},t.safeMode=function(){r=!0},t.versionString=oX,t.regex={concat:Kn,lookahead:hk,either:sg,optional:kL,anyNumberOfTimes:xL};for(let P in rc)typeof rc[P]=="object"&&ak(rc[P]);return Object.assign(t,rc),t},Jr=yk({});Jr.newInstance=()=>yk({});Sk.exports=Jr;Jr.HighlightJS=Jr;Jr.default=Jr});var EX={};zk(EX,{Compartment:()=>ii,EditorState:()=>ce,EditorView:()=>T,HighlightStyle:()=>Wt,MergeView:()=>Fa,StreamLanguage:()=>Xs,autocompletion:()=>Wb,baseExtensions:()=>mX,bracketMatching:()=>Tf,closeBrackets:()=>Qu,closeBracketsKeymap:()=>Pu,crosshairC Line truncated
`){[e,i]=nr(this,e,i);let r="";for(let s=0,o=0;s<=i&&o<this.text.length;o++){let l=this.text[o],a=s+l.length;s>e&&o&&(r+=n),e<a&&i>s&&(r+=l.slice(Math.max(0,e-s),i-s)),s=a+1}return r}flatten(e){for(let i of this.text)e.push(i)}scanIdentical(){return 0}static split(e,i){let n=[],r=-1;for(let s of e)n.push(s),r+=s.length+1,n.length==32&&(i.push(new t(n,r)),n=[],r=-1);return r>-1&&i.push(new t(n,r)),i}},er=class t extends te{constructor(e,i){super(),this.children=e,this.length=i,this.lines=0;for(let n of e)this.lines+=n.lines}lineInner(e,i,n,r){for(let s=0;;s++){let o=this.children[s],l=r+o.length,a=n+o.lines-1;if((i?a:l)>=e)return o.lineInner(e,i,n,r);r=l+1,n=a+1}}decompose(e,i,n,r){for(let s=0,o=0;o<=i&&s<this.children.length;s++){let l=this.children[s],a=o+l.length;if(e<=a&&i>=o){let h=r&((o<=e?1:0)|(a>=i?2:0));o>=e&&a<=i&&!h?n.push(l):l.decompose(e-o,i-o,n,h)}o=a+1}}replace(e,i,n){if([e,i]=nr(this,e,i),n.lines<this.lines)for(let r=0,s=0;r<this.children.length;r++){let o=this.children[r],l=s+o.length;if(e>=s&&i<=l){let a=o.replace(e-s,i-s,n),h=this.lines-o.lines+a.lines;if(a.lines<h>>4&&a.lines>h>>6){let c=this.children.slice();return c[r]=a,new t(c,this.length-(i-e)+n.length)}return super.replace(s,l,a)}s=l+1}return super.replace(e,i,n)}sliceString(e,i=this.length,n=`
`){[e,i]=nr(this,e,i);let r="";for(let s=0,o=0;s<this.children.length&&o<=i;s++){let l=this.children[s],a=o+l.length;o>e&&s&&(r+=n),e<a&&i>o&&(r+=l.sliceString(e-o,i-o,n)),o=a+1}return r}flatten(e){for(let i of this.children)i.flatten(e)}scanIdentical(e,i){if(!(e instanceof t))return 0;let n=0,[r,s,o,l]=i>0?[0,0,this.children.length,e.children.length]:[this.children.length-1,e.children.length-1,-1,-1];for(;;r+=i,s+=i){if(r==o||s==l)return n;let a=this.children[r],h=e.children[s];if(a!=h)return n+a.scanIdentical(h,i);n+=a.length+1}}static from(e,i=e.reduce((n,r)=>n+r.length+1,-1)){let n=0;for(let d of e)n+=d.lines;if(n<32){let d=[];for(let p of e)p.flatten(d);return new kt(d,i)}let r=Math.max(32,n>>5),s=r<<1,o=r>>1,l=[],a=0,h=-1,c=[];function f(d){let p;if(d.lines>s&&d instanceof t)for(let g of d.children)f(g);else d.lines>o&&(a>o||!a)?(u(),l.push(d)):d instanceof kt&&a&&(p=c[c.length-1])instanceof kt&&d.lines+p.lines<=32?(a+=d.lines,h+=d.length+1,c[c.length-1]=new kt(p.text.concat(d.text),p.length+1+d.length)):(a+d.lines>r&&u(),a+=d.lines,h+=d.length+1,c.push(d))}function u(){a!=0&&(l.push(c.length==1?c[0]:t.from(c,h)),h=-1,a=c.length=0)}for(let d of e)f(d);return u(),l.length==1?l[0]:new t(l,i)}};te.empty=new kt([""],0);function Gk(t){let e=-1;for(let i of t)e+=i.length+1;return e}function Ao(t,e,i=0,n=1e9){for(let r=0,s=0,o=!0;s<t.length&&r<=n;s++){let l=t[s],a=r+l.length;a>=i&&(a>n&&(l=l.slice(0,n-r)),r<i&&(l=l.slice(i-r)),o?(e[e.length-1]+=l,o=!1):e.push(l)),r=a+1}return e}function vg(t,e,i){return Ao(t,[""],e,i)}var hn=class{constructor(e,i=1){this.dir=i,this.done=!1,this.lineBreak=!1,this.value="",this.nodes=[e],this.offsets=[i>0?1:(e instanceof kt?e.text.length:e.children.length)<<1]}nextInner(e,i){for(this.done=this.lineBreak=!1;;){let n=this.nodes.length-1,r=this.nodes[n],s=this.offsets[n],o=s>>1,l=r instanceof kt?r.text.length:r.children.length;if(o==(i>0?l:0)){if(n==0)return this.done=!0,this.value="",this;i>0&&this.offsets[n-1]++,this.nodes.pop(),this.offsets.pop()}else if((s&1)==(i>0?0:1)){if(this.offsets[n]+=i,e==0)return this.lineBreak=!0,this.value=`
`,this;e--}else if(r instanceof kt){let a=r.text[o+(i<0?-1:0)];if(this.offsets[n]+=i,a.length>Math.max(0,e))return this.value=e==0?a:i>0?a.slice(e):a.slice(0,a.length-e),this;e-=a.length}else{let a=r.children[o+(i<0?-1:0)];e>a.length?(e-=a.length,this.offsets[n]+=i):(i<0&&this.offsets[n]--,this.nodes.push(a),this.offsets.push(i>0?1:(a instanceof kt?a.text.length:a.children.length)<<1))}}}next(e=0){return e<0&&(this.nextInner(-e,-this.dir),e=this.value.length),this.nextInner(e,this.dir)}},Ro=class{constructor(e,i,n){this.value="",this.done=!1,this.cursor=new hn(e,i>n?-1:1),this.pos=i>n?e.length:0,this.from=Math.min(i,n),this.to=Math.max(i,n)}nextInner(e,i){if(i<0?this.pos<=this.from:this.pos>=this.to)return this.value="",this.done=!0,this;e+=Math.max(0,i<0?this.pos-this.to:this.from-this.pos);let n=i<0?this.pos-this.from:this.to-this.pos;e>n&&(e=n),n-=e;let{value:r}=this.cursor.next(e);return this.pos+=(r.length+e)*i,this.value=r.length<=n?r:i<0?r.slice(r.length-n):r.slice(0,n),this.done=!this.value,this}next(e=0){return e<0?e=Math.max(e,this.from-this.pos):e>0&&(e=Math.min(e,this.to-this.pos)),this.nextInner(e,this.cursor.dir)}get lineBreak(){return this.cursor.lineBreak&&this.value!=""}},Eo=class{constructor(e){this.inner=e,this.afterBreak=!0,this.value="",this.done=!1}next(e=0){let{done:i,lineBreak:n,value:r}=this.inner.next(e);return i&&this.afterBreak?(this.value="",this.afterBreak=!1):i?(this.done=!0,this.value=""):n?this.afterBreak?this.value="":(this.afterBreak=!0,this.next()):(this.value=r,this.afterBreak=!1),this}get lineBreak(){return!1}};typeof Symbol!="undefined"&&(te.prototype[Symbol.iterator]=function(){return this.iter()},hn.prototype[Symbol.iterator]=Ro.prototype[Symbol.iterator]=Eo.prototype[Symbol.iterator]=function(){return this});var mc=class{constructor(e,i,n,r){this.from=e,this.to=i,this.number=n,this.text=r}get length(){return this.to-this.from}};function nr(t,e,i){return e=Math.max(0,Math.min(t.length,e)),[e,Math.max(e,Math.min(t.length,i))]}function Xe(t,e,i=!0,n=!0){return Sg(t,e,i,n)}function Uk(t){return t>=56320&&t<57344}function Fk(t){return t>=55296&&t<56320}function We(t,e){let i=t.charCodeAt(e);if(!Fk(i)||e+1==t.length)return i;let n=t.charCodeAt(e+1);return Uk(n)?(i-55296<<10)+(n-56320)+65536:i}function os(t){return t<=65535?String.fromCharCode(t):(t-=65536,String.fromCharCode((t>>10)+55296,(t&1023)+56320))}function wt(t){return t<65536?1:2}var bc=/\r\n?|\n/,De=(function(t){return t[t.Simple=0]="Simple",t[t.TrackDel=1]="TrackDel",t[t.TrackBefore=2]="TrackBefore",t[t.TrackAfter=3]="TrackAfter",t})(De||(De={})),yi=class t{constructor(e){this.sections=e}get length(){let e=0;for(let i=0;i<this.sections.length;i+=2)e+=this.sections[i];return e}get newLength(){let e=0;for(let i=0;i<this.sections.length;i+=2){let n=this.sections[i+1];e+=n<0?this.sections[i]:n}return e}get empty(){return this.sections.length==0||this.sections.length==2&&this.sections[1]<0}iterGaps(e){for(let i=0,n=0,r=0;i<this.sections.length;){let s=this.sections[i++],o=this.sections[i++];o<0?(e(n,r,s),r+=s):r+=o,n+=s}}iterChangedRanges(e,i=!1){yc(this,e,i)}get invertedDesc(){let e=[];for(let i=0;i<this.sections.length;){let n=this.sections[i++],r=this.sections[i++];r<0?e.push(n,r):e.push(r,n)}return new t(e)}composeDesc(e){return this.empty?e:e.empty?this:Ag(this,e)}mapDesc(e,i=!1){return e.empty?this:Sc(this,e,i)}mapPos(e,i=-1,n=De.Simple){let r=0,s=0;for(let o=0;o<this.sections.length;){let l=this.sections[o++],a=this.sections[o++],h=r+l;if(a<0){if(h>e)return s+(e-r);s+=l}else{if(n!=De.Simple&&h>=e&&(n==De.TrackDel&&r<e&&h>e||n==De.TrackBefore&&r<e||n==De.TrackAfter&&h>e))return null;if(h>e||h==e&&i<0&&!l)return e==r||i<0?s:s+a;s+=a}r=h}if(e>r)throw new RangeError(`Position ${e} is out of range for changeset of length ${r}`);return s}touchesRange(e,i=e){for(let n=0,r=0;n<this.sections.length&&r<=i;){let s=this.sections[n++],o=this.sections[n++],l=r+s;if(o>=0&&r<=i&&l>=e)return r<e&&l>i?"cover":!0;r=l}return!1}toString(){let e="";for(let i=0;i<this.sections.length;){let n=this.sections[i++],r=this.sections[i++];e+=(e?" ":"")+n+(r>=0?":"+r:"")}return e}toJSON(){return this.sections}static fromJSON(e){if(!Array.isArray(e)||e.length%2||e.some(i=>typeof i!="number"))throw new RangeError("Invalid JSON representation of ChangeDesc");return new t(e)}static create(e){return new t(e)}},qe=class t extends yi{constructor(e,i){super(e),this.inserted=i}apply(e){if(this.length!=e.length)throw new RangeError("Applying change set to a document with the wrong length");return yc(this,(i,n,r,s,o)=>e=e.replace(r,r+(n-i),o),!1),e}mapDesc(e,i=!1){return Sc(this,e,i,!0)}invert(e){let i=this.sections.slice(),n=[];for(let r=0,s=0;r<i.length;r+=2){let o=i[r],l=i[r+1];if(l>=0){i[r]=l,i[r+1]=o;let a=r>>1;for(;n.length<a;)n.push(te.empty);n.push(o?e.slice(s,s+o):te.empty)}s+=o}return new t(i,n)}compose(e){return this.empty?e:e.empty?this:Ag(this,e,!0)}map(e,i=!1){return e.empty?this:Sc(this,e,i,!0)}iterChanges(e,i=!1){yc(this,e,i)}get desc Line truncated
`}get readOnly(){return this.facet(Zg)}phrase(e,...i){for(let n of this.facet(t.phrases))if(Object.prototype.hasOwnProperty.call(n,e)){e=n[e];break}return i.length&&(e=e.replace(/\$(\$|\d*)/g,(n,r)=>{if(r=="$")return"$";let s=+(r||1);return!s||s>i.length?n:i[s-1]})),e}languageDataAt(e,i,n=-1){let r=[];for(let s of this.facet(Eg))for(let o of s(this,i,n))Object.prototype.hasOwnProperty.call(o,e)&&r.push(o[e]);return r}charCategorizer(e){return sw(this.languageDataAt("wordChars",e).join(""))}wordAt(e){let{text:i,from:n,length:r}=this.doc.lineAt(e),s=this.charCategorizer(e),o=e-n,l=e-n;for(;o>0;){let a=Xe(i,o,!1);if(s(i.slice(a,o))!=xe.Word)break;o=a}for(;l<r;){let a=Xe(i,l);if(s(i.slice(l,a))!=xe.Word)break;l=a}return o==l?null:v.range(o+n,l+n)}};ce.allowMultipleSelections=kc;ce.tabSize=R.define({combine:t=>t.length?t[0]:4});ce.lineSeparator=Mg;ce.readOnly=Zg;ce.phrases=R.define({compare(t,e){let i=Object.keys(t),n=Object.keys(e);return i.length==n.length&&i.every(r=>t[r]==e[r])}});ce.languageData=Eg;ce.changeFilter=Lg;ce.transactionFilter=Xg;ce.transactionExtender=_g;ii.reconfigure=q.define();function Ge(t,e,i={}){let n={};for(let r of t)for(let s of Object.keys(r)){let o=r[s],l=n[s];if(l===void 0)n[s]=o;else if(!(l===o||o===void 0))if(Object.hasOwnProperty.call(i,s))n[s]=i[s](l,o);else throw new Error("Config merge conflict for field "+s)}for(let r in e)n[r]===void 0&&(n[r]=e[r]);return n}var Nt=class{eq(e){return this==e}range(e,i=e){return rs.create(e,i,this)}};Nt.prototype.startSide=Nt.prototype.endSide=0;Nt.prototype.point=!1;Nt.prototype.mapMode=De.TrackDel;var rs=class t{constructor(e,i,n){this.from=e,this.to=i,this.value=n}static create(e,i,n){return new t(e,i,n)}};function $c(t,e){return t.from-e.from||t.value.startSide-e.value.startSide}var Tc=class t{constructor(e,i,n,r){this.from=e,this.to=i,this.value=n,this.maxPoint=r}get length(){return this.to[this.to.length-1]}findIndex(e,i,n,r=0){let s=n?this.to:this.from;for(let o=r,l=s.length;;){if(o==l)return o;let a=o+l>>1,h=s[a]-e||(n?this.value[a].endSide:this.value[a].startSide)-i;if(a==o)return h>=0?o:l;h>=0?l=a:o=a+1}}between(e,i,n,r){for(let s=this.findIndex(i,-1e9,!0),o=this.findIndex(n,1e9,!1,s);s<o;s++)if(r(this.from[s]+e,this.to[s]+e,this.value[s])===!1)return!1}map(e,i){let n=[],r=[],s=[],o=-1,l=-1;for(let a=0;a<this.value.length;a++){let h=this.value[a],c=this.from[a]+e,f=this.to[a]+e,u,d;if(c==f){let p=i.mapPos(c,h.startSide,h.mapMode);if(p==null||(u=d=p,h.startSide!=h.endSide&&(d=i.mapPos(c,h.endSide),d<u)))continue}else if(u=i.mapPos(c,h.startSide),d=i.mapPos(f,h.endSide),u>d||u==d&&h.startSide>0&&h.endSide<=0)continue;(d-u||h.endSide-h.startSide)<0||(o<0&&(o=u),h.point&&(l=Math.max(l,d-u)),n.push(h),r.push(u-o),s.push(d-o))}return{mapped:n.length?new t(r,s,n,l):null,pos:o}}},re=class t{constructor(e,i,n,r){this.chunkPos=e,this.chunk=i,this.nextLayer=n,this.maxPoint=r}static create(e,i,n,r){return new t(e,i,n,r)}get length(){let e=this.chunk.length-1;return e<0?0:Math.max(this.chunkEnd(e),this.nextLayer.length)}get size(){if(this.isEmpty)return 0;let e=this.nextLayer.size;for(let i of this.chunk)e+=i.value.length;return e}chunkEnd(e){return this.chunkPos[e]+this.chunk[e].length}update(e){let{add:i=[],sort:n=!1,filterFrom:r=0,filterTo:s=this.length}=e,o=e.filter;if(i.length==0&&!o)return this;if(n&&(i=i.slice().sort($c)),this.isEmpty)return i.length?t.of(i):this;let l=new _o(this,null,-1).goto(0),a=0,h=[],c=new Ee;for(;l.value||a<i.length;)if(a<i.length&&(l.from-i[a].from||l.startSide-i[a].value.startSide)>=0){let f=i[a++];c.addInner(f.from,f.to,f.value)||h.push(f)}else l.rangeIndex==1&&l.chunkIndex<this.chunk.length&&(a==i.length||this.chunkEnd(l.chunkIndex)<i[a].from)&&(!o||r>this.chunkEnd(l.chunkIndex)||s<this.chunkPos[l.chunkIndex])&&c.addChunk(this.chunkPos[l.chunkIndex],this.chunk[l.chunkIndex])?l.nextChunk():((!o||r>l.to||s<l.from||o(l.from,l.to,l.value))&&(c.addInner(l.from,l.to,l.value)||h.push(rs.create(l.from,l.to,l.value))),l.next());return c.finishInner(this.nextLayer.isEmpty&&!h.length?t.empty:this.nextLayer.update({add:h,filter:o,filterFrom:r,filterTo:s}))}map(e){if(e.empty||this.isEmpty)return this;let i=[],n=[],r=-1;for(let o=0;o<this.chunk.length;o++){let l=this.chunkPos[o],a=this.chunk[o],h=e.touchesRange(l,l+a.length);if(h===!1)r=Math.max(r,a.maxPoint),i.push(a),n.push(e.mapPos(l));else if(h===!0){let{mapped:c,pos:f}=a.map(l,e);c&&(r=Math.max(r,c.maxPoint),i.push(c),n.push(f))}}let s=this.nextLayer.map(e);return i.length==0?s:new t(n,i,s||t.empty,r)}between(e,i,n){if(!this.isEmpty){for(let r=0;r<this.chunk.length;r++){let s=this.chunkPos[r],o=this.chunk[r];if(i>=s&&e<=s+o.length&&o.between(s,e-s,i-s,n)===!1)return}this.nextLayer.between(e,i,n)}}iter(e=0){return ss.from([this]).goto(e)}get isEmpty(){return this.nextLayer==this}static iter(e,i=0){return ss.from(e).goto(i)}static compare(e,i,n,r,s=-1){let o=e.filter(f=>f.maxPoint>0||!f.isEmpty&&f.maxPoint>=s),l=i.filter(f=>f.maxPoint>0||!f.isEmpty&&f.maxPoint>=s),a=$g(o,l Line truncated
`)}static newName(){let e=Ng[Bg]||1;return Ng[Bg]=e+1,"\u037C"+e.toString(36)}static mount(e,i,n){let r=e[Ec],s=n&&n.nonce;r?s&&r.setNonce(s):r=new Mc(e,s),r.mount(Array.isArray(i)?i:[i],e)}},jg=new Map,Mc=class{constructor(e,i){let n=e.ownerDocument||e,r=n.defaultView;if(!e.head&&e.adoptedStyleSheets&&r.CSSStyleSheet){let s=jg.get(n);if(s)return e[Ec]=s;this.sheet=new r.CSSStyleSheet,jg.set(n,this)}else this.styleTag=n.createElement("style"),i&&this.styleTag.setAttribute("nonce",i);this.modules=[],e[Ec]=this}mount(e,i){let n=this.sheet,r=0,s=0;for(let o=0;o<e.length;o++){let l=e[o],a=this.modules.indexOf(l);if(a<s&&a>-1&&(this.modules.splice(a,1),s--,a=-1),a==-1){if(this.modules.splice(s++,0,l),n)for(let h=0;h<l.rules.length;h++)n.insertRule(l.rules[h],r++)}else{for(;s<a;)r+=this.modules[s++].rules.length;r+=l.rules.length,s++}}if(n)i.adoptedStyleSheets.indexOf(this.sheet)<0&&(i.adoptedStyleSheets=[this.sheet,...i.adoptedStyleSheets]);else{let o="";for(let a=0;a<this.modules.length;a++)o+=this.modules[a].getRules()+`
`;this.styleTag.textContent=o;let l=i.head||i;this.styleTag.parentNode!=l&&l.insertBefore(this.styleTag,l.firstChild)}}setNonce(e){this.styleTag&&this.styleTag.getAttribute("nonce")!=e&&this.styleTag.setAttribute("nonce",e)}};var Si={8:"Backspace",9:"Tab",10:"Enter",12:"NumLock",13:"Enter",16:"Shift",17:"Control",18:"Alt",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",44:"PrintScreen",45:"Insert",46:"Delete",59:";",61:"=",91:"Meta",92:"Meta",106:"*",107:"+",108:",",109:"-",110:".",111:"/",144:"NumLock",145:"ScrollLock",160:"Shift",161:"Shift",162:"Control",163:"Control",164:"Alt",165:"Alt",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},rr={48:")",49:"!",50:"@",51:"#",52:"$",53:"%",54:"^",55:"&",56:"*",57:"(",59:":",61:"+",173:"_",186:":",187:"+",188:"<",189:"_",190:">",191:"?",192:"~",219:"{",220:"|",221:"}",222:'"'},lw=typeof navigator!="undefined"&&/Mac/.test(navigator.platform),aw=typeof navigator!="undefined"&&/MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);for(_e=0;_e<10;_e++)Si[48+_e]=Si[96+_e]=String(_e);var _e;for(_e=1;_e<=24;_e++)Si[_e+111]="F"+_e;var _e;for(_e=65;_e<=90;_e++)Si[_e]=String.fromCharCode(_e+32),rr[_e]=String.fromCharCode(_e);var _e;for(Do in Si)rr.hasOwnProperty(Do)||(rr[Do]=Si[Do]);var Do;function zg(t){var e=lw&&t.metaKey&&t.shiftKey&&!t.ctrlKey&&!t.altKey||aw&&t.shiftKey&&t.key&&t.key.length==1||t.key=="Unidentified",i=!e&&t.key||(t.shiftKey?rr:Si)[t.keyCode]||t.key||"Unidentified";return i=="Esc"&&(i="Escape"),i=="Del"&&(i="Delete"),i=="Left"&&(i="ArrowLeft"),i=="Up"&&(i="ArrowUp"),i=="Right"&&(i="ArrowRight"),i=="Down"&&(i="ArrowDown"),i}function ge(){var t=arguments[0];typeof t=="string"&&(t=document.createElement(t));var e=1,i=arguments[1];if(i&&typeof i=="object"&&i.nodeType==null&&!Array.isArray(i)){for(var n in i)if(Object.prototype.hasOwnProperty.call(i,n)){var r=i[n];typeof r=="string"?t.setAttribute(n,r):r!=null&&(t[n]=r)}e++}for(;e<arguments.length;e++)Yg(t,arguments[e]);return t}function Yg(t,e){if(typeof e=="string")t.appendChild(document.createTextNode(e));else if(e!=null)if(e.nodeType!=null)t.appendChild(e);else if(Array.isArray(e))for(var i=0;i<e.length;i++)Yg(t,e[i]);else throw new RangeError("Unsupported child node: "+e)}var st=typeof navigator!="undefined"?navigator:{userAgent:"",vendor:"",platform:""},Nc=typeof document!="undefined"?document:{documentElement:{style:{}}},jc=/Edge\/(\d+)/.exec(st.userAgent),MO=/MSIE \d/.test(st.userAgent),zc=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(st.userAgent),Ol=!!(MO||zc||jc),qg=!Ol&&/gecko\/(\d+)/i.test(st.userAgent),Lc=!Ol&&/Chrome\/(\d+)/.exec(st.userAgent),Wg="webkitFontSmoothing"in Nc.documentElement.style,Yc=!Ol&&/Apple Computer/.test(st.vendor),Vg=Yc&&(/Mobile\/\w+/.test(st.userAgent)||st.maxTouchPoints>2),Z={mac:Vg||/Mac/.test(st.platform),windows:/Win/.test(st.platform),linux:/Linux|X11/.test(st.platform),ie:Ol,ie_version:MO?Nc.documentMode||6:zc?+zc[1]:jc?+jc[1]:0,gecko:qg,gecko_version:qg?+(/Firefox\/(\d+)/.exec(st.userAgent)||[0,0])[1]:0,chrome:!!Lc,chrome_version:Lc?+Lc[1]:0,ios:Vg,android:/Android\b/.test(st.userAgent),webkit:Wg,webkit_version:Wg?+(/\bAppleWebKit\/(\d+)/.exec(st.userAgent)||[0,0])[1]:0,safari:Yc,safari_version:Yc?+(/\bVersion\/(\d+(\.\d+)?)/.exec(st.userAgent)||[0,0])[1]:0,tabSize:Nc.documentElement.style.tabSize!=null?"tab-size":"-moz-tab-size"};function ys(t){let e;return t.nodeType==11?e=t.getSelection?t:t.ownerDocument:e=t,e.getSelection()}function qc(t,e){return e?t==e||t.contains(e.nodeType!=1?e.parentNode:e):!1}function Uo(t,e){if(!e.anchorNode)return!1;try{return qc(t,e.anchorNode)}catch{return!1}}function hr(t){return t.nodeType==3?gn(t,0,t.nodeValue.length).getClientRects():t.nodeType==1?t.getClientRects():[]}function fs(t,e,i,n){return i?Gg(t,e,i,n,-1)||Gg(t,e,i,n,1):!1}function pn(t){for(var e=0;;e++)if(t=t.previousSibling,!t)return e}function tl(t){return t.nodeType==1&&/^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(t.nodeName)}function Gg(t,e,i,n,r){for(;;){if(t==i&&e==n)return!0;if(e==(r<0?0:li(t))){if(t.nodeName=="DIV")return!1;let s=t.parentNode;if(!s||s.nodeType!=1)return!1;e=pn(t)+(r<0?0:1),t=s}else if(t.nodeType==1){if(t=t.childNodes[e+(r<0?-1:0)],t.nodeType==1&&t.contentEditable=="false")return!1;e=r<0?li(t):0}else return!1}}function li(t){return t.nodeType==3?t.nodeValue.length:t.childNodes.length}function $s(t,e){let i=e?t.left:t.right;return{left:i,right:i,top:t.top,bottom:t.bottom}}function cw(t){let e=t.visualViewport;return e?{left:0,right:e.width,top:0,bottom:e.height}:{left:0,right:t.innerWidth,top:0,bottom:t.innerHeight}}function LO(t,e){let i=e.width/t.offsetWidth,n=e.height/t.offsetHeight;return(i>.995&&i<1.005||!isFinite(i)||Math.abs(e.width-t.offsetWidth)<1)&&(i=1),(n>.995&&n<1.005||!isFinite(n)||Math.abs(e.height-t.offsetHeight)<1)&&(n=1),{scaleX:i,scaleY:n}}function hw(t,e,i,n,r,Line truncated
`,r=t.state.doc.line(r.number+(i?1:-1)),s=t.bidiSpans(r),h=t.visualLineSide(r,!i)}if(a){if(!a(c))return l}else{if(!n)return h;a=n(c)}l=h}}function zw(t,e,i){let n=t.state.charCategorizer(e),r=n(i);return s=>{let o=n(s);return r==xe.Space&&(r=o),r==o}}function Yw(t,e,i,n){let r=e.head,s=i?1:-1;if(r==(i?t.state.doc.length:0))return v.cursor(r,e.assoc);let o=e.goalColumn,l,a=t.contentDOM.getBoundingClientRect(),h=t.coordsAtPos(r,e.assoc||-1),c=t.documentTop;if(h)o==null&&(o=h.left-a.left),l=s<0?h.top:h.bottom;else{let d=t.viewState.lineBlockAt(r);o==null&&(o=Math.min(a.right-a.left,t.defaultCharacterWidth*(r-d.from))),l=(s<0?d.top:d.bottom)+c}let f=a.left+o,u=n!=null?n:t.viewState.heightOracle.textHeight>>1;for(let d=0;;d+=10){let p=l+(u+d)*s,g=um(t,{x:f,y:p},!1,s);if(p<a.top||p>a.bottom||(s<0?g<r:g>r)){let m=t.docView.coordsForChar(g),b=!m||p<m.top?-1:1;return v.cursor(g,b,void 0,o)}}}function gs(t,e,i){for(;;){let n=0;for(let r of t)r.between(e-1,e+1,(s,o,l)=>{if(e>s&&e<o){let a=n||i||(e-s<o-e?-1:1);e=a<0?s:o,n=a}});if(!n)return e}}function pm(t,e){let i=null;for(let n=0;n<e.ranges.length;n++){let r=e.ranges[n],s=null;if(r.empty){let o=gs(t,r.from,0);o!=r.from&&(s=v.cursor(o,-1))}else{let o=gs(t,r.from,-1),l=gs(t,r.to,1);(o!=r.from||l!=r.to)&&(s=v.range(r.from==r.anchor?o:l,r.from==r.head?o:l))}s&&(i||(i=e.ranges.slice()),i[n]=s)}return i?v.create(i,e.mainIndex):e}function _c(t,e,i){let n=gs(t.state.facet(Ts).map(r=>r(t)),i.from,e.head>i.from?-1:1);return n==i.from?i:v.cursor(n,n<i.from?1:-1)}var as="\uFFFF",th=class{constructor(e,i){this.points=e,this.text="",this.lineSeparator=i.facet(ce.lineSeparator)}append(e){this.text+=e}lineBreak(){this.text+=as}readRange(e,i){if(!e)return this;let n=e.parentNode;for(let r=e;;){this.findPointBefore(n,r);let s=this.text.length;this.readNode(r);let o=r.nextSibling;if(o==i)break;let l=ve.get(r),a=ve.get(o);(l&&a?l.breakAfter:(l?l.breakAfter:tl(r))||tl(o)&&(r.nodeName!="BR"||r.cmIgnore)&&this.text.length>s)&&!Ww(o,i)&&this.lineBreak(),r=o}return this.findPointBefore(n,i),this}readTextNode(e){let i=e.nodeValue;for(let n of this.points)n.node==e&&(n.pos=this.text.length+Math.min(n.offset,i.length));for(let n=0,r=this.lineSeparator?null:/\r\n?|\n/g;;){let s=-1,o=1,l;if(this.lineSeparator?(s=i.indexOf(this.lineSeparator,n),o=this.lineSeparator.length):(l=r.exec(i))&&(s=l.index,o=l[0].length),this.append(i.slice(n,s<0?i.length:s)),s<0)break;if(this.lineBreak(),o>1)for(let a of this.points)a.node==e&&a.pos>this.text.length&&(a.pos-=o-1);n=s+o}}readNode(e){if(e.cmIgnore)return;let i=ve.get(e),n=i&&i.overrideDOMText;if(n!=null){this.findPointInside(e,n.length);for(let r=n.iter();!r.next().done;)r.lineBreak?this.lineBreak():this.append(r.value)}else e.nodeType==3?this.readTextNode(e):e.nodeName=="BR"?e.nextSibling&&this.lineBreak():e.nodeType==1&&this.readRange(e.firstChild,null)}findPointBefore(e,i){for(let n of this.points)n.node==e&&e.childNodes[n.offset]==i&&(n.pos=this.text.length)}findPointInside(e,i){for(let n of this.points)(e.nodeType==3?n.node==e:e.contains(n.node))&&(n.pos=this.text.length+(qw(e,n.node,n.offset)?i:0))}};function qw(t,e,i){for(;;){if(!e||i<li(e))return!1;if(e==t)return!0;i=pn(e)+1,e=e.parentNode}}function Ww(t,e){let i;for(;!(t==e||!t);t=t.nextSibling){let n=ve.get(t);if(!(n!=null&&n.isWidget||t.cmIgnore))return!1;n&&(i||(i=[])).push(n)}if(i)for(let n of i){let r=n.overrideDOMText;if(r!=null&&r.length)return!1}return!0}var ol=class{constructor(e,i){this.node=e,this.offset=i,this.pos=-1}},ih=class{constructor(e,i,n,r){this.typeOver=r,this.bounds=null,this.text="",this.domChanged=i>-1;let{impreciseHead:s,impreciseAnchor:o}=e.docView;if(e.state.readOnly&&i>-1)this.newSel=null;else if(i>-1&&(this.bounds=e.docView.domBoundsAround(i,n,0))){let l=s||o?[]:Gw(e),a=new th(l,e.state);a.readRange(this.bounds.startDOM,this.bounds.endDOM),this.text=a.text,this.newSel=Uw(l,this.bounds.from)}else{let l=e.observer.selectionRange,a=s&&s.node==l.focusNode&&s.offset==l.focusOffset||!qc(e.contentDOM,l.focusNode)?e.state.selection.main.head:e.docView.posFromDOM(l.focusNode,l.focusOffset),h=o&&o.node==l.anchorNode&&o.offset==l.anchorOffset||!qc(e.contentDOM,l.anchorNode)?e.state.selection.main.anchor:e.docView.posFromDOM(l.anchorNode,l.anchorOffset),c=e.viewport;if((Z.ios||Z.chrome)&&e.state.selection.main.empty&&a!=h&&(c.from>0||c.to<e.state.doc.length)){let f=Math.min(a,h),u=Math.max(a,h),d=c.from-f,p=c.to-u;(d==0||d==1||f==0)&&(p==0||p==-1||u==e.state.doc.length)&&(a=0,h=e.state.doc.length)}e.inputState.composing>-1&&e.state.selection.ranges.length>1?this.newSel=e.state.selection.replaceRange(v.range(h,a)):this.newSel=v.single(h,a)}}};function gm(t,e){let i,{newSel:n}=e,r=t.state.selection.main,s=t.inputState.lastKeyTime>Date.now()-100?t.inputState.lastKeyCode:-1;if(e.bounds){let{from:o,to:l}=e.bounds,a=r.from,h=null;(s===8||Z.android&&e.text.length<l-o)&&(a=r.to,h="end");let c=Om(t.state.doc.sliceString(o,l,as),e.text,a-o,h);c&&(Z.chrome&&s==13&&c.toB==c.from+2&&e.text.sl Line truncated
`&&t.lineWrapping&&(n&&(n=v.single(n.main.anchor-1,n.main.head-1)),i={from:r.from,to:r.to,insert:te.of([" "])}),i)return _h(t,i,n,s);if(n&&!n.main.eq(r)){let o=!1,l="select";return t.inputState.lastSelectionTime>Date.now()-50&&(t.inputState.lastSelectionOrigin=="select"&&(o=!0),l=t.inputState.lastSelectionOrigin,l=="select.pointer"&&(n=pm(t.state.facet(Ts).map(a=>a(t)),n))),t.dispatch({selection:n,scrollIntoView:o,userEvent:l}),!0}else return!1}function _h(t,e,i,n=-1){if(Z.ios&&t.inputState.flushIOSKey(e))return!0;let r=t.state.selection.main;if(Z.android&&(e.to==r.to&&(e.from==r.from||e.from==r.from-1&&t.state.sliceDoc(e.from,r.from)==" ")&&e.insert.length==1&&e.insert.lines==2&&cr(t.contentDOM,"Enter",13)||(e.from==r.from-1&&e.to==r.to&&e.insert.length==0||n==8&&e.insert.length<e.to-e.from&&e.to>r.head)&&cr(t.contentDOM,"Backspace",8)||e.from==r.from&&e.to==r.to+1&&e.insert.length==0&&cr(t.contentDOM,"Delete",46)))return!0;let s=e.insert.toString();t.inputState.composing>=0&&t.inputState.composing++;let o,l=()=>o||(o=Vw(t,e,i));return t.state.facet(tm).some(a=>a(t,e.from,e.to,s,l))||t.dispatch(l()),!0}function Vw(t,e,i){let n,r=t.state,s=r.selection.main,o=-1;if(e.from==e.to&&e.from<s.from||e.from>s.to){let a=e.from<s.from?-1:1,h=a<0?s.from:s.to,c=gs(r.facet(Ts).map(f=>f(t)),h,a);e.from==c&&(o=c)}if(o>-1)n={changes:e,selection:v.cursor(e.from+e.insert.length,-1)};else if(e.from>=s.from&&e.to<=s.to&&e.to-e.from>=(s.to-s.from)/3&&(!i||i.main.empty&&i.main.from==e.from+e.insert.length)&&t.inputState.composing<0){let a=s.from<e.from?r.sliceDoc(s.from,e.from):"",h=s.to>e.to?r.sliceDoc(e.to,s.to):"";n=r.replaceSelection(t.state.toText(a+e.insert.sliceString(0,void 0,t.state.lineBreak)+h))}else{let a=r.changes(e),h=i&&i.main.to<=a.newLength?i.main:void 0;if(r.selection.ranges.length>1&&(t.inputState.composing>=0||t.inputState.compositionPendingChange)&&e.to<=s.to+10&&e.to>=s.to-10){let c=t.state.sliceDoc(e.from,e.to),f,u=i&&fm(t,i.main.head);if(u){let p=e.insert.length-(e.to-e.from);f={from:u.from,to:u.to-p}}else f=t.state.doc.lineAt(s.head);let d=s.to-e.to;n=r.changeByRange(p=>{if(p.from==s.from&&p.to==s.to)return{changes:a,range:h||p.map(a)};let g=p.to-d,m=g-c.length;if(t.state.sliceDoc(m,g)!=c||g>=f.from&&m<=f.to)return{range:p};let b=r.changes({from:m,to:g,insert:e.insert}),y=p.to-s.to;return{changes:b,range:h?v.range(Math.max(0,h.anchor+y),Math.max(0,h.head+y)):p.map(b)}})}else n={changes:a,selection:h&&r.selection.replaceRange(h)}}let l="input.type";return(t.composing||t.inputState.compositionPendingChange&&t.inputState.compositionEndedAt>Date.now()-50)&&(t.inputState.compositionPendingChange=!1,l+=".compose",t.inputState.compositionFirstChange&&(l+=".start",t.inputState.compositionFirstChange=!1)),r.update(n,{userEvent:l,scrollIntoView:!0})}function Om(t,e,i,n){let r=Math.min(t.length,e.length),s=0;for(;s<r&&t.charCodeAt(s)==e.charCodeAt(s);)s++;if(s==r&&t.length==e.length)return null;let o=t.length,l=e.length;for(;o>0&&l>0&&t.charCodeAt(o-1)==e.charCodeAt(l-1);)o--,l--;if(n=="end"){let a=Math.max(0,s-Math.min(o,l));i-=o+a-s}if(o<s&&t.length<e.length){let a=i<=s&&i>=o?s-i:0;s-=a,l=s+(l-o),o=s}else if(l<s){let a=i<=s&&i>=l?s-i:0;s-=a,o=s+(o-l),l=s}return{from:s,toA:o,toB:l}}function Gw(t){let e=[];if(t.root.activeElement!=t.contentDOM)return e;let{anchorNode:i,anchorOffset:n,focusNode:r,focusOffset:s}=t.observer.selectionRange;return i&&(e.push(new ol(i,n)),(r!=i||s!=n)&&e.push(new ol(r,s))),e}function Uw(t,e){if(t.length==0)return null;let i=t[0].pos,n=t.length==2?t[1].pos:i;return i>-1&&n>-1?v.single(i+e,n+e):null}var nh=class{setSelectionOrigin(e){this.lastSelectionOrigin=e,this.lastSelectionTime=Date.now()}constructor(e){this.view=e,this.lastKeyCode=0,this.lastKeyTime=0,this.lastTouchTime=0,this.lastFocusTime=0,this.lastScrollTop=0,this.lastScrollLeft=0,this.pendingIOSKey=void 0,this.tabFocusMode=-1,this.lastSelectionOrigin=null,this.lastSelectionTime=0,this.lastContextMenu=0,this.scrollHandlers=[],this.handlers=Object.create(null),this.composing=-1,this.compositionFirstChange=null,this.compositionEndedAt=0,this.compositionPendingKey=!1,this.compositionPendingChange=!1,this.insertingText="",this.insertingTextAt=0,this.mouseSelection=null,this.draggedContent=null,this.handleEvent=this.handleEvent.bind(this),this.notifiedFocused=e.hasFocus,Z.safari&&e.contentDOM.addEventListener("input",()=>null),Z.gecko&&hv(e.contentDOM.ownerDocument)}handleEvent(e){!iv(this.view,e)||this.ignoreDuringComposition(e)||e.type=="keydown"&&this.keydown(e)||(this.view.updateState!=0?Promise.resolve().then(()=>this.runHandlers(e.type,e)):this.runHandlers(e.type,e))}runHandlers(e,i){let n=this.handlers[e];if(n){for(let r of n.observers)r(this.view,i);for(let r of n.handlers){if(i.defaultPrevented)break;if(r(this.view,i)){i.preventDefault();break}}}}ensureHandlers(e){let i=Fw(e),n=this.handlers,r=this.view.contentDOM;for(let s in i)if(s!="scroll"){let o=!i[s].handlers.length,l=n[s];l&&o!=!l.handlers.length&&(r.removeEventListe Line truncated
`))};if((Z.mac||Z.android)&&f.from==o-1&&/^\. ?$/.test(n.text)&&e.contentDOM.getAttribute("autocorrect")=="off"&&(f={from:l,to:a,insert:te.of([n.text.replace("."," ")])}),this.pendingContextChange=f,!e.state.readOnly){let u=this.to-this.from+(f.to-f.from+f.insert.length);_h(e,f,v.single(this.toEditorPos(n.selectionStart,u),this.toEditorPos(n.selectionEnd,u)))}this.pendingContextChange&&(this.revertPending(e.state),this.setSelection(e.state)),f.from<f.to&&!f.insert.length&&e.inputState.composing>=0&&!/[\\p{Alphabetic}\\p{Number}_]/.test(i.text.slice(Math.max(0,n.updateRangeStart-1),Math.min(i.text.length,n.updateRangeStart+1)))&&this.handlers.compositionend(n)},this.handlers.characterboundsupdate=n=>{let r=[],s=null;for(let o=this.toEditorPos(n.rangeStart),l=this.toEditorPos(n.rangeEnd);o<l;o++){let a=e.coordsForChar(o);s=a&&new DOMRect(a.left,a.top,a.right-a.left,a.bottom-a.top)||s||new DOMRect,r.push(s)}i.updateCharacterBounds(n.rangeStart,r)},this.handlers.textformatupdate=n=>{let r=[];for(let s of n.getTextFormats()){let o=s.underlineStyle,l=s.underlineThickness;if(!/none/i.test(o)&&!/none/i.test(l)){let a=this.toEditorPos(s.rangeStart),h=this.toEditorPos(s.rangeEnd);if(a<h){let c=`text-decoration: underline ${/^[a-z]/.test(o)?o+" ":o=="Dashed"?"dashed ":o=="Squiggle"?"wavy ":""}${/thin/i.test(l)?1:2}px`;r.push(E.mark({attributes:{style:c}}).range(a,h))}}}e.dispatch({effects:om.of(E.set(r))})},this.handlers.compositionstart=()=>{e.inputState.composing<0&&(e.inputState.composing=0,e.inputState.compositionFirstChange=!0)},this.handlers.compositionend=()=>{if(e.inputState.composing=-1,e.inputState.compositionFirstChange=null,this.composing){let{drifted:n}=this.composing;this.composing=null,n&&this.reset(e.state)}};for(let n in this.handlers)i.addEventListener(n,this.handlers[n]);this.measureReq={read:n=>{this.editContext.updateControlBounds(n.contentDOM.getBoundingClientRect());let r=ys(n.root);r&&r.rangeCount&&this.editContext.updateSelectionBounds(r.getRangeAt(0).getBoundingClientRect())}}}applyEdits(e){let i=0,n=!1,r=this.pendingContextChange;return e.changes.iterChanges((s,o,l,a,h)=>{if(n)return;let c=h.length-(o-s);if(r&&o>=r.to)if(r.from==s&&r.to==o&&r.insert.eq(h)){r=this.pendingContextChange=null,i+=c,this.to+=c;return}else r=null,this.revertPending(e.state);if(s+=i,o+=i,o<=this.from)this.from+=c,this.to+=c;else if(s<this.to){if(s<this.from||o>this.to||this.to-this.from+h.length>3e4){n=!0;return}this.editContext.updateText(this.toContextPos(s),this.toContextPos(o),h.toString()),this.to+=c}i+=c}),r&&!n&&this.revertPending(e.state),!n}update(e){let i=this.pendingContextChange,n=e.startState.selection.main;this.composing&&(this.composing.drifted||!e.changes.touchesRange(n.from,n.to)&&e.transactions.some(r=>!r.isUserEvent("input.type")&&r.changes.touchesRange(this.from,this.to)))?(this.composing.drifted=!0,this.composing.editorBase=e.changes.mapPos(this.composing.editorBase)):!this.applyEdits(e)||!this.rangeIsValid(e.state)?(this.pendingContextChange=null,this.reset(e.state)):(e.docChanged||e.selectionSet||i)&&this.setSelection(e.state),(e.geometryChanged||e.docChanged||e.selectionSet)&&e.view.requestMeasure(this.measureReq)}resetRange(e){let{head:i}=e.selection.main;this.from=Math.max(0,i-1e4),this.to=Math.min(e.doc.length,i+1e4)}reset(e){this.resetRange(e),this.editContext.updateText(0,this.editContext.text.length,e.doc.sliceString(this.from,this.to)),this.setSelection(e)}revertPending(e){let i=this.pendingContextChange;this.pendingContextChange=null,this.editContext.updateText(this.toContextPos(i.from),this.toContextPos(i.from+i.insert.length),e.doc.sliceString(i.from,i.to))}setSelection(e){let{main:i}=e.selection,n=this.toContextPos(Math.max(this.from,Math.min(this.to,i.anchor))),r=this.toContextPos(i.head);(this.editContext.selectionStart!=n||this.editContext.selectionEnd!=r)&&this.editContext.updateSelection(n,r)}rangeIsValid(e){let{head:i}=e.selection.main;return!(this.from>0&&i-this.from<500||this.to<e.doc.length&&this.to-i<500||this.to-this.from>1e4*3)}toEditorPos(e,i=this.to-this.from){e=Math.min(e,i);let n=this.composing;return n&&n.drifted?n.editorBase+(e-n.contextBase):e+this.from}toContextPos(e){let i=this.composing;return i&&i.drifted?i.contextBase+(e-i.editorBase):e-this.from}destroy(){for(let e in this.handlers)this.editContext.removeEventListener(e,this.handlers[e])}},T=class t{get state(){return this.viewState.state}get viewport(){return this.viewState.viewport}get visibleRanges(){return this.viewState.visibleRanges}get inView(){return this.viewState.inView}get composing(){return!!this.inputState&&this.inputState.composing>0}get compositionStarted(){return!!this.inputState&&this.inputState.composing>=0}get root(){return this._root}get win(){return this.dom.ownerDocument.defaultView||window}constructor(e={}){var i;this.plugins=[],this.pluginMap=new Map,this.editorAttrs={},this.contentAttrs={},this.bidiCache=[],this.destroyed=!1,this.updateState=2,this.measureScheduled=-1,this.measureR Line truncated
-\x7F-\x9F\xAD\u061C\u200B\u200E\u200F\u2028\u2029\u202D\u202E\u2066\u2067\u2069\uFEFF\uFFF9-\uFFFC]`,xh),Xv={0:"null",7:"bell",8:"backspace",10:"newline",11:"vertical tab",13:"carriage return",27:"escape",8203:"zero width space",8204:"zero width non-joiner",8205:"zero width joiner",8206:"left-to-right mark",8207:"right-to-left mark",8232:"line separator",8237:"left-to-right override",8238:"right-to-left override",8294:"left-to-right isolate",8295:"right-to-left isolate",8297:"pop directional isolate",8233:"paragraph separator",65279:"zero width no-break space",65532:"object replacement"},Dc=null;function _v(){var t;if(Dc==null&&typeof document!="undefined"&&document.body){let e=document.body.style;Dc=((t=e.tabSize)!==null&&t!==void 0?t:e.MozTabSize)!=null}return Dc||!1}var Jo=R.define({combine(t){let e=Ge(t,{render:null,specialChars:Lv,addSpecialChars:null});return(e.replaceTabs=!_v())&&(e.specialChars=new RegExp(" |"+e.specialChars.source,xh)),e.addSpecialChars&&(e.specialChars=new RegExp(e.specialChars.source+"|"+e.addSpecialChars.source,xh)),e}});function Ih(t={}){return[Jo.of(t),Zv()]}var QO=null;function Zv(){return QO||(QO=Se.fromClass(class{constructor(t){this.view=t,this.decorations=E.none,this.decorationCache=Object.create(null),this.decorator=this.makeDecorator(t.state.facet(Jo)),this.decorations=this.decorator.createDeco(t)}makeDecorator(t){return new Sh({regexp:t.specialChars,decoration:(e,i,n)=>{let{doc:r}=i.state,s=We(e[0],0);if(s==9){let o=r.lineAt(n),l=i.state.tabSize,a=rt(o.text,l,n-o.from);return E.replace({widget:new wh((l-a%l)*this.view.defaultCharacterWidth/this.view.scaleX)})}return this.decorationCache[s]||(this.decorationCache[s]=E.replace({widget:new kh(t,s)}))},boundary:t.replaceTabs?void 0:/[^]/})}update(t){let e=t.state.facet(Jo);t.startState.facet(Jo)!=e?(this.decorator=this.makeDecorator(e),this.decorations=this.decorator.createDeco(t.view)):this.decorations=this.decorator.updateDeco(t,this.decorations)}},{decorations:t=>t.decorations}))}var Dv="\u2022";function Iv(t){return t>=32?Dv:t==10?"\u2424":String.fromCharCode(9216+t)}var kh=class extends Be{constructor(e,i){super(),this.options=e,this.code=i}eq(e){return e.code==this.code}toDOM(e){let i=Iv(this.code),n=e.state.phrase("Control character")+" "+(Xv[this.code]||"0x"+this.code.toString(16)),r=this.options.render&&this.options.render(this.code,n,i);if(r)return r;let s=document.createElement("span");return s.textContent=i,s.title=n,s.setAttribute("aria-label",n),s.className="cm-specialChar",s}ignoreEvent(){return!1}},wh=class extends Be{constructor(e){super(),this.width=e}eq(e){return e.width==this.width}toDOM(){let e=document.createElement("span");return e.textContent=" ",e.className="cm-tab",e.style.width=this.width+"px",e}ignoreEvent(){return!1}};function Bh(){return Nv}var Bv=E.line({class:"cm-activeLine"}),Nv=Se.fromClass(class{constructor(t){this.decorations=this.getDeco(t)}update(t){(t.docChanged||t.selectionSet)&&(this.decorations=this.getDeco(t.view))}getDeco(t){let e=-1,i=[];for(let n of t.state.selection.ranges){let r=t.lineBlockAt(n.head);r.from>e&&(i.push(Bv.range(r.from)),e=r.from)}return E.set(i)}},{decorations:t=>t.decorations}),vh=class extends Be{constructor(e){super(),this.content=e}toDOM(e){let i=document.createElement("span");return i.className="cm-placeholder",i.style.pointerEvents="none",i.appendChild(typeof this.content=="string"?document.createTextNode(this.content):typeof this.content=="function"?this.content(e):this.content.cloneNode(!0)),i.setAttribute("aria-hidden","true"),i}coordsAt(e){let i=e.firstChild?hr(e.firstChild):[];if(!i.length)return null;let n=window.getComputedStyle(e.parentNode),r=$s(i[0],n.direction!="rtl"),s=parseInt(n.lineHeight);return r.bottom-r.top>s*1.5?{left:r.left,right:r.right,top:r.top,bottom:r.top+s}:r}ignoreEvent(){return!1}};function Xm(t){let e=Se.fromClass(class{constructor(i){this.view=i,this.placeholder=t?E.set([E.widget({widget:new vh(t),side:1}).range(0)]):E.none}get decorations(){return this.view.state.doc.length?E.none:this.placeholder}},{decorations:i=>i.decorations});return typeof t=="string"?[e,T.contentAttributes.of({"aria-placeholder":t})]:e}var Qh=2e3;function jv(t,e,i){let n=Math.min(e.line,i.line),r=Math.max(e.line,i.line),s=[];if(e.off>Qh||i.off>Qh||e.col<0||i.col<0){let o=Math.min(e.off,i.off),l=Math.max(e.off,i.off);for(let a=n;a<=r;a++){let h=t.doc.line(a);h.length<=l&&s.push(v.range(h.from+o,h.to+l))}}else{let o=Math.min(e.col,i.col),l=Math.max(e.col,i.col);for(let a=n;a<=r;a++){let h=t.doc.line(a),c=Zo(h.text,o,t.tabSize,!0);if(c<0)s.push(v.cursor(h.to));else{let f=Zo(h.text,l,t.tabSize);s.push(v.range(h.from+c,h.from+f))}}}return s}function zv(t,e){let i=t.coordsAtPos(t.viewport.from);return i?Math.round(Math.abs((i.left-e)/t.defaultCharacterWidth)):-1}function PO(t,e){let i=t.posAtCoords({x:e.clientX,y:e.clientY},!1),n=t.state.doc.lineAt(i),r=i-n.from,s=r>Qh?-1:r==n.length?zv(t,e.clientX):rt(n.text,t.state.tabSize,i-n.from);return{line:n.numbe Line truncated
`&&(i="");else{let n=i.indexOf(`
`);n>-1&&(i=i.slice(0,n))}return e+i.length<=this.to?i:i.slice(0,this.to-e)}nextLine(){let e=this.parsedPos,i=this.lineAfter(e),n=e+i.length;for(let r=this.rangeIndex;;){let s=this.ranges[r].to;if(s>=n||(i=i.slice(0,s-(n-i.length)),r++,r==this.ranges.length))break;let o=this.ranges[r].from,l=this.lineAfter(o);i+=l,n=o+l.length}return{line:i,end:n}}skipGapsTo(e,i,n){for(;;){let r=this.ranges[this.rangeIndex].to,s=e+i;if(n>0?r>s:r>=s)break;let o=this.ranges[++this.rangeIndex].from;i+=o-r}return i}moveRangeIndex(){for(;this.ranges[this.rangeIndex].to<this.parsedPos;)this.rangeIndex++}emitToken(e,i,n,r){let s=4;if(this.ranges.length>1){r=this.skipGapsTo(i,r,1),i+=r;let l=this.chunk.length;r=this.skipGapsTo(n,r,-1),n+=r,s+=this.chunk.length-l}let o=this.chunk.length-4;return this.lang.streamParser.mergeTokens&&s==4&&o>=0&&this.chunk[o]==e&&this.chunk[o+2]==i?this.chunk[o+2]=n:this.chunk.push(e,i,n,s),r}parseLine(e){let{line:i,end:n}=this.nextLine(),r=0,{streamParser:s}=this.lang,o=new Tl(i,e?e.state.tabSize:4,e?qt(e.state):2);if(o.eol())s.blankLine(this.state,o.indentUnit);else for(;!o.eol();){let l=S0(s.token,o,this.state);if(l&&(r=this.emitToken(this.lang.tokenTable.resolve(l),this.parsedPos+o.start,this.parsedPos+o.pos,r)),o.start>1e4)break}this.parsedPos=n,this.moveRangeIndex(),this.parsedPos<this.to&&this.parsedPos++}finishChunk(){let e=fe.build({buffer:this.chunk,start:this.chunkStart,length:this.parsedPos-this.chunkStart,nodeSet:JQ,topID:0,maxBufferLength:2048,reused:this.chunkReused});e=new fe(e.type,e.children,e.positions,e.length,[[this.lang.stateAfter,this.lang.streamParser.copyState(this.state)]]),this.chunks.push(e),this.chunkPos.push(this.chunkStart-this.ranges[0].from),this.chunk=[],this.chunkReused=void 0,this.chunkStart=this.parsedPos}finish(){return new fe(this.lang.topNode,this.chunks,this.chunkPos,this.parsedPos-this.ranges[0].from).balance()}};function S0(t,e,i){e.start=e.pos;for(let n=0;n<10;n++){let r=t(e,i);if(e.pos>e.start)return r}throw new Error("Stream parser failed to advance stream.")}var Rf=Object.create(null),_s=[Ne.none],JQ=new Or(_s),n0=[],r0=Object.create(null),x0=Object.create(null);for(let[t,e]of[["variable","variableName"],["variable-2","variableName.special"],["string-2","string.special"],["def","variableName.definition"],["tag","tagName"],["attribute","attributeName"],["type","typeName"],["builtin","variableName.standard"],["qualifier","modifier"],["error","invalid"],["header","heading"],["property","propertyName"]])x0[t]=k0(Rf,e);var Cl=class{constructor(e){this.extra=e,this.table=Object.assign(Object.create(null),x0)}resolve(e){return e?this.table[e]||(this.table[e]=k0(this.extra,e)):0}},eP=new Cl(Rf);function pf(t,e){n0.indexOf(t)>-1||(n0.push(t),console.warn(e))}function k0(t,e){let i=[];for(let l of e.split(" ")){let a=[];for(let h of l.split(".")){let c=t[h]||O[h];c?typeof c=="function"?a.length?a=a.map(c):pf(h,`Modifier ${h} used at start of tag`):a.length?pf(h,`Tag ${h} used as modifier`):a=Array.isArray(c)?c:[c]:pf(h,`Unknown highlighting tag ${h}`)}for(let h of a)i.push(h)}if(!i.length)return 0;let n=e.replace(/ /g,"_"),r=n+" "+i.map(l=>l.id),s=r0[r];if(s)return s.id;let o=r0[r]=Ne.define({id:_s.length,name:n,props:[at({[n]:i})]});return _s.push(o),o.id}function tP(t,e){let i=Ne.define({id:_s.length,name:"Document",props:[vi.add(()=>t),Et.add(()=>n=>e.getIndent(n))],top:!0});return _s.push(i),i}var u_={rtl:E.mark({class:"cm-iso",inclusive:!0,attributes:{dir:"rtl"},bidiIsolate:ke.RTL}),ltr:E.mark({class:"cm-iso",inclusive:!0,attributes:{dir:"ltr"},bidiIsolate:ke.LTR}),auto:E.mark({class:"cm-iso",inclusive:!0,attributes:{dir:"auto"},bidiIsolate:null})};var Zf=t=>{let{state:e}=t,i=e.doc.lineAt(e.selection.main.from),n=If(t.state,i.from);return n.line?iP(t):n.block?rP(t):!1};function Df(t,e){return({state:i,dispatch:n})=>{if(i.readOnly)return!1;let r=t(e,i);return r?(n(i.update(r)),!0):!1}}var iP=Df(lP,0);var nP=Df(R0,0);var rP=Df((t,e)=>R0(t,e,oP(e)),0);function If(t,e){let i=t.languageDataAt("commentTokens",e);return i.length?i[0]:{}}var Is=50;function sP(t,{open:e,close:i},n,r){let s=t.sliceDoc(n-Is,n),o=t.sliceDoc(r,r+Is),l=/\s*$/.exec(s)[0].length,a=/^\s*/.exec(o)[0].length,h=s.length-l;if(s.slice(h-e.length,h)==e&&o.slice(a,a+i.length)==i)return{open:{pos:n-l,margin:l&&1},close:{pos:r+a,margin:a&&1}};let c,f;r-n<=2*Is?c=f=t.sliceDoc(n,r):(c=t.sliceDoc(n,n+Is),f=t.sliceDoc(r-Is,r));let u=/^\s*/.exec(c)[0].length,d=/\s*$/.exec(f)[0].length,p=f.length-d-i.length;return c.slice(u,u+e.length)==e&&f.slice(p,p+i.length)==i?{open:{pos:n+u+e.length,margin:/\s/.test(c.charAt(u+e.length))?1:0},close:{pos:r-d-i.length,margin:/\s/.test(f.charAt(p-1))?1:0}}:null}function oP(t){let e=[];for(let i of t.selection.ranges){let n=t.doc.lineAt(i.from),r=i.to<=n.to?n:t.doc.lineAt(i.to);r.from>n.from&&r.from==i.to&&(r=i.to==n.to+1?n:t.doc.lineAt(i.to-1));let s=e.length-1;s>=0&&e[s].to>n.from?e[s].to=r.to:e.push({from:n.from+/^\s*/.exec(n.text)[0].length,to:r.to})}return e}function R Line truncated
`+i.scrub(),s=this.advance(r);return s>-1&&s<r.length?this.complete(e,n,s):!1}finish(e,i){return(this.stage==2||this.stage==3)&&Ks(i.content,this.pos)==i.content.length?this.complete(e,i,i.content.length):!1}complete(e,i,n){return e.addLeafElement(i,se(C.LinkReference,this.start,this.start+n,this.elts)),!0}nextStage(e){return e?(this.pos=e.to-this.start,this.elts.push(e),this.stage++,!0):(e===!1&&(this.stage=-1),!1)}advance(e){for(;;){if(this.stage==-1)return-1;if(this.stage==0){if(!this.nextStage(Ay(e,this.pos,this.start,!0)))return-1;if(e.charCodeAt(this.pos)!=58)return this.stage=-1;this.elts.push(se(C.LinkMark,this.pos+this.start,this.pos+this.start+1)),this.pos++}else if(this.stage==1){if(!this.nextStage(Ty(e,Ks(e,this.pos),this.start)))return-1}else if(this.stage==2){let i=Ks(e,this.pos),n=0;if(i>this.pos){let r=Cy(e,i,this.start);if(r){let s=Du(e,r.to-this.start);s>0&&(this.nextStage(r),n=s)}}return n||(n=Du(e,this.pos)),n>0&&n<e.length?n:-1}else return Du(e,this.pos)}}};function Du(t,e){for(;e<t.length;e++){let i=t.charCodeAt(e);if(i==10)break;if(!Dt(i))return-1}return e}var qu=class{nextLine(e,i,n){let r=i.depth<e.stack.length?-1:yy(i),s=i.next;if(r<0)return!1;let o=se(C.HeaderMark,e.lineStart+i.pos,e.lineStart+r);return e.nextLine(),e.addLeafElement(n,se(s==61?C.SetextHeading1:C.SetextHeading2,n.start,e.prevLineEnd(),[...e.parser.parseInline(n.content,n.start),o])),!0}finish(){return!1}},wy={LinkReference(t,e){return e.content.charCodeAt(0)==91?new Yu(e):null},SetextHeading(){return new qu}},LT=[(t,e)=>by(e)>=0,(t,e)=>gy(e)>=0,(t,e)=>Oy(e)>=0,(t,e)=>Ku(e,t,!0)>=0,(t,e)=>Ju(e,t,!0)>=0,(t,e)=>Hu(e,t,!0)>=0,(t,e)=>ky(e,t,!0)>=0],XT={text:"",end:0},Wu=class{constructor(e,i,n,r){this.parser=e,this.input=i,this.ranges=r,this.line=new Nu,this.atEnd=!1,this.reusePlaceholders=new Map,this.stoppedAt=null,this.rangeI=0,this.to=r[r.length-1].to,this.lineStart=this.absoluteLineStart=this.absoluteLineEnd=r[0].from,this.block=ia.create(C.Document,0,this.lineStart,0,0),this.stack=[this.block],this.fragments=n.length?new Uu(n,i):null,this.readLine()}get parsedPos(){return this.absoluteLineStart}advance(){if(this.stoppedAt!=null&&this.absoluteLineStart>this.stoppedAt)return this.finish();let{line:e}=this;for(;;){for(let n=0;;){let r=e.depth<this.stack.length?this.stack[this.stack.length-1]:null;for(;n<e.markers.length&&(!r||e.markers[n].from<r.end);){let s=e.markers[n++];this.addNode(s.type,s.from,s.to)}if(!r)break;this.finishContext()}if(e.pos<e.text.length)break;if(!this.nextLine())return this.finish()}if(this.fragments&&this.reuseFragment(e.basePos))return null;e:for(;;){for(let n of this.parser.blockParsers)if(n){let r=n(this,e);if(r!=!1){if(r==!0)return null;e.forward();continue e}}break}let i=new Bu(this.lineStart+e.pos,e.text.slice(e.pos));for(let n of this.parser.leafBlockParsers)if(n){let r=n(this,i);r&&i.parsers.push(r)}e:for(;this.nextLine()&&e.pos!=e.text.length;){if(e.indent<e.baseIndent+4){for(let n of this.parser.endLeafBlock)if(n(this,e,i))break e}for(let n of i.parsers)if(n.nextLine(this,e,i))return null;i.content+=`
`+e.scrub();for(let n of e.markers)i.marks.push(n)}return this.finishLeaf(i),null}stopAt(e){if(this.stoppedAt!=null&&this.stoppedAt<e)throw new RangeError("Can't move stoppedAt forward");this.stoppedAt=e}reuseFragment(e){if(!this.fragments.moveTo(this.absoluteLineStart+e,this.absoluteLineStart)||!this.fragments.matches(this.block.hash))return!1;let i=this.fragments.takeNodes(this);return i?(this.absoluteLineStart+=i,this.lineStart=Ry(this.absoluteLineStart,this.ranges),this.moveRangeI(),this.absoluteLineStart<this.to?(this.lineStart++,this.absoluteLineStart++,this.readLine()):(this.atEnd=!0,this.readLine()),!0):!1}get depth(){return this.stack.length}parentType(e=this.depth-1){return this.parser.nodeSet.types[this.stack[e].type]}nextLine(){return this.lineStart+=this.line.text.length,this.absoluteLineEnd>=this.to?(this.absoluteLineStart=this.absoluteLineEnd,this.atEnd=!0,this.readLine(),!1):(this.lineStart++,this.absoluteLineStart=this.absoluteLineEnd+1,this.moveRangeI(),this.readLine(),!0)}peekLine(){return this.scanLine(this.absoluteLineEnd+1).text}moveRangeI(){for(;this.rangeI<this.ranges.length-1&&this.absoluteLineStart>=this.ranges[this.rangeI].to;)this.rangeI++,this.absoluteLineStart=Math.max(this.absoluteLineStart,this.ranges[this.rangeI].from)}scanLine(e){let i=XT;if(i.end=e,e>=this.to)i.text="";else if(i.text=this.lineChunkAt(e),i.end+=i.text.length,this.ranges.length>1){let n=this.absoluteLineStart,r=this.rangeI;for(;this.ranges[r].to<i.end;){r++;let s=this.ranges[r].from,o=this.lineChunkAt(s);i.end=s+o.length,i.text=i.text.slice(0,this.ranges[r-1].to-n)+o,n=i.end-i.text.length}}return i}readLine(){let{line:e}=this,{text:i,end:n}=this.scanLine(this.absoluteLineStart);for(this.absoluteLineEnd=n,e.reset(i);e.depth<this.stack.length;e.depth++){let r=this.stack[e.depth],s=this.parser.skipContextMarkup[r.type];if(!s)throw new Error("Unhandled block context "+C[r.type]);let o=this.line.markers.length;if(!s(r,this,e)){this.line.markers.length>o&&(r.end=this.line.markers[this.line.markers.length-1].to),e.forward();break}e.forward()}}lineChunkAt(e){let i=this.input.chunk(e),n;if(this.input.lineChunks)n=i==`
`?"":i;else{let r=i.indexOf(`
`);n=r<0?i:i.slice(0,r)}return e+n.length>this.to?n.slice(0,this.to-e):n}prevLineEnd(){return this.atEnd?this.lineStart:this.lineStart-1}startContext(e,i,n=0){this.block=ia.create(e,n,this.lineStart+i,this.block.hash,this.lineStart+this.line.text.length),this.stack.push(this.block)}startComposite(e,i,n=0){this.startContext(this.parser.getNodeType(e),i,n)}addNode(e,i,n){typeof e=="number"&&(e=new Me(this.parser.nodeSet.types[e],Er,Er,(n!=null?n:this.prevLineEnd())-i)),this.block.addChild(e,i-this.block.from)}addElement(e){this.block.addChild(e.toTree(this.parser.nodeSet),e.from-this.block.from)}addLeafElement(e,i){this.addNode(this.buffer.writeElements(Gu(i.children,e.marks),-i.from).finish(i.type,i.to-i.from),i.from)}finishContext(){let e=this.stack.pop(),i=this.stack[this.stack.length-1];i.addChild(e.toTree(this.parser.nodeSet),e.from-i.from),this.block=i}finish(){for(;this.stack.length>1;)this.finishContext();return this.addGaps(this.block.toTree(this.parser.nodeSet,this.lineStart))}addGaps(e){return this.ranges.length>1?vy(this.ranges,0,e.topNode,this.ranges[0].from,this.reusePlaceholders):e}finishLeaf(e){for(let n of e.parsers)if(n.finish(this,e))return;let i=Gu(this.parser.parseInline(e.content,e.start),e.marks);this.addNode(this.buffer.writeElements(i,-e.start).finish(C.Paragraph,e.content.length),e.start)}elt(e,i,n,r){return typeof e=="string"?se(this.parser.getNodeType(e),i,n,r):new ra(e,i)}get buffer(){return new na(this.parser.nodeSet)}};function vy(t,e,i,n,r){let s=t[e].to,o=[],l=[],a=i.from+n;function h(c,f){for(;f?c>=s:c>s;){let u=t[e+1].from-s;n+=u,c+=u,e++,s=t[e].to}}for(let c=i.firstChild;c;c=c.nextSibling){h(c.from+n,!0);let f=c.from+n,u,d=r.get(c.tree);d?u=d:c.to+n>s?(u=vy(t,e,c,n,r),h(c.to+n,!1)):u=c.toTree(),o.push(u),l.push(f-a)}return h(i.to+n,!1),new Me(i.type,o,l,i.to+n-a,i.tree?i.tree.propValues:void 0)}var eo=class t extends Hl{constructor(e,i,n,r,s,o,l,a,h){super(),this.nodeSet=e,this.blockParsers=i,this.leafBlockParsers=n,this.blockNames=r,this.endLeafBlock=s,this.skipContextMarkup=o,this.inlineParsers=l,this.inlineNames=a,this.wrappers=h,this.nodeTypes=Object.create(null);for(let c of e.types)this.nodeTypes[c.name]=c.id}createParse(e,i,n){let r=new Wu(this,e,i,n);for(let s of this.wrappers)r=s(r,e,i,n);return r}configure(e){let i=Vu(e);if(!i)return this;let{nodeSet:n,skipContextMarkup:r}=this,s=this.blockParsers.slice(),o=this.leafBlockParsers.slice(),l=this.blockNames.slice(),a=this.inlineParsers.slice(),h=this.inlineNames.slice(),c=this.endLeafBlock.slice(),f=this.wrappers;if(Hs(i.defineNodes)){r=Object.assign({},r);let u=n.types.slice(),d;for(let p of i.defineNodes){let{name:g,block:m,composite:b,style:y}=typeof p=="string"?{name:p}:p;if(u.some(S=>S.name==g))continue;b&&(r[u.length]=(S,k,w)=>b(k,w,S.value));let x=u.length,Q=b?["Block","BlockContext"]:m?x>=C.ATXHeading1&&x<=C.SetextHeading2?["Block","LeafBlock","Heading"]:["Block","LeafBlock"]:void 0;u.push(tt.define({id:x,name:g,props:Q&&[[ue.group,Q]]})),y&&(d||(d={}),Array.isArray(y)||y instanceof Pe?d[g]=y:Object.assign(d,y))}n=new Gs(u),d&&(n=n.extend(at(d)))}if(Hs(i.props)&&(n=n.extend(...i.props)),Hs(i.remove))for(let u of i.remove){let d=this.blockNames.indexOf(u),p=this.inlineNames.indexOf(u);d>-1&&(s[d]=o[d]=void 0),p>-1&&(a[p]=void 0)}if(Hs(i.parseBlock))for(let u of i.parseBlock){let d=l.indexOf(u.name);if(d>-1)s[d]=u.parse,o[d]=u.leaf;else{let p=u.before?ta(l,u.before):u.after?ta(l,u.after)+1:l.length-1;s.splice(p,0,u.parse),o.splice(p,0,u.leaf),l.splice(p,0,u.name)}u.endLeaf&&c.push(u.endLeaf)}if(Hs(i.parseInline))for(let u of i.parseInline){let d=h.indexOf(u.name);if(d>-1)a[d]=u.parse;else{let p=u.before?ta(h,u.before):u.after?ta(h,u.after)+1:h.length-1;a.splice(p,0,u.parse),h.splice(p,0,u.name)}}return i.wrap&&(f=f.concat(i.wrap)),new t(n,s,o,l,c,r,a,h,f)}getNodeType(e){let i=this.nodeTypes[e];if(i==null)throw new RangeError(`Unknown node type '${e}'`);return i}parseInline(e,i){let n=new io(this,e,i);e:for(let r=i;r<n.end;){let s=n.char(r);for(let o of this.inlineParsers)if(o){let l=o(n,s,r);if(l>=0){r=l;continue e}}r++}return n.resolveMarkers(0)}};function Hs(t){return t!=null&&t.length>0}function Vu(t){if(!Array.isArray(t))return t;if(t.length==0)return null;let e=Vu(t[0]);if(t.length==1)return e;let i=Vu(t.slice(1));if(!i||!e)return e||i;let n=(o,l)=>(o||Er).concat(l||Er),r=e.wrap,s=i.wrap;return{props:n(e.props,i.props),defineNodes:n(e.defineNodes,i.defineNodes),parseBlock:n(e.parseBlock,i.parseBlock),parseInline:n(e.parseInline,i.parseInline),remove:n(e.remove,i.remove),wrap:r?s?(o,l,a,h)=>r(s(o,l,a,h),l,a,h):r:s}}function ta(t,e){let i=t.indexOf(e);if(i<0)throw new RangeError(`Position specified relative to unknown parser ${e}`);return i}var Qy=[tt.none];for(let t=1,e;e=C[t];t++)Qy[t]=tt.define({id:t,name:e,props:t>=C.Escape?[]:[[ue.group,t in py?["Block","BlockContext"]:["Block","LeafBlock"]]],top:e=="Document"});var Er=[],na=class{constructor(e){this.nodeSet=e,this.content=[],this.nodes=[]}write(e,i,n, Line truncated
`;)s--;this.fragmentEnd=s?s-1:0}let n=this.cursor;n||(n=this.cursor=this.fragment.tree.cursor(),n.firstChild());let r=e+this.fragment.offset;for(;n.to<=r;)if(!n.parent())return!1;for(;;){if(n.from>=r)return this.fragment.from<=i;if(!n.childAfter(r))return!1}}matches(e){let i=this.cursor.tree;return i&&i.prop(ue.contextHash)==e}takeNodes(e){let i=this.cursor,n=this.fragment.offset,r=this.fragmentEnd-(this.fragment.openEnd?1:0),s=e.absoluteLineStart,o=s,l=e.block.children.length,a=o,h=l;for(;;){if(i.to-n>r){if(i.type.isAnonymous&&i.firstChild())continue;break}let c=Ry(i.from-n,e.ranges);if(i.to-n<=e.ranges[e.rangeI].to)e.addNode(i.tree,c);else{let f=new Me(e.parser.nodeSet.types[C.Paragraph],[],[],0,e.block.hashProp);e.reusePlaceholders.set(f,i.tree),e.addNode(f,c)}if(i.type.is("Block")&&(ZT.indexOf(i.type.id)<0?(o=i.to-n,l=e.block.children.length):(o=a,l=h),a=i.to-n,h=e.block.children.length),!i.nextSibling())break}for(;e.block.children.length>l;)e.block.children.pop(),e.block.positions.pop();return o-s}};function Ry(t,e){let i=t;for(let n=1;n<e.length;n++){let r=e[n-1].to,s=e[n].from;r<t&&(i-=s-r)}return i}var DT=at({"Blockquote/...":O.quote,HorizontalRule:O.contentSeparator,"ATXHeading1/... SetextHeading1/...":O.heading1,"ATXHeading2/... SetextHeading2/...":O.heading2,"ATXHeading3/...":O.heading3,"ATXHeading4/...":O.heading4,"ATXHeading5/...":O.heading5,"ATXHeading6/...":O.heading6,"Comment CommentBlock":O.comment,Escape:O.escape,Entity:O.character,"Emphasis/...":O.emphasis,"StrongEmphasis/...":O.strong,"Link/... Image/...":O.link,"OrderedList/... BulletList/...":O.list,"BlockQuote/...":O.quote,"InlineCode CodeText":O.monospace,"URL Autolink":O.url,"HeaderMark HardBreak QuoteMark ListMark LinkMark EmphasisMark CodeMark":O.processingInstruction,"CodeInfo LinkLabel":O.labelName,LinkTitle:O.string,Paragraph:O.content}),Ey=new eo(new Gs(Qy).extend(DT),Object.keys(ea).map(t=>ea[t]),Object.keys(ea).map(t=>wy[t]),Object.keys(ea),LT,py,Object.keys(Iu).map(t=>Iu[t]),Object.keys(Iu),[]);function IT(t,e,i){let n=[];for(let r=t.firstChild,s=e;;r=r.nextSibling){let o=r?r.from:i;if(o>s&&n.push({from:s,to:o}),!r)break;s=r.to}return n}function My(t){let{codeParser:e,htmlParser:i}=t;return{wrap:iy((r,s)=>{let o=r.type.id;if(e&&(o==C.CodeBlock||o==C.FencedCode)){let l="";if(o==C.FencedCode){let h=r.node.getChild(C.CodeInfo);h&&(l=s.read(h.from,h.to))}let a=e(l);if(a)return{parser:a,overlay:h=>h.type.id==C.CodeText,bracketed:o==C.FencedCode}}else if(i&&(o==C.HTMLBlock||o==C.HTMLTag||o==C.CommentBlock))return{parser:i,overlay:IT(r.node,r.from,r.to)};return null})}}var BT={resolve:"Strikethrough",mark:"StrikethroughMark"},NT={defineNodes:[{name:"Strikethrough",style:{"Strikethrough/...":O.strikethrough}},{name:"StrikethroughMark",style:O.processingInstruction}],parseInline:[{name:"Strikethrough",parse(t,e,i){if(e!=126||t.char(i+1)!=126||t.char(i+2)==126)return-1;let n=t.slice(i-1,i),r=t.slice(i+2,i+3),s=/\s|^$/.test(n),o=/\s|^$/.test(r),l=to.test(n),a=to.test(r);return t.addDelimiter(BT,i,i+2,!o&&(!a||s||l),!s&&(!l||o||a))},after:"Emphasis"}]};function Js(t,e,i=0,n,r=0){let s=0,o=!0,l=-1,a=-1,h=!1,c=()=>{n.push(t.elt("TableCell",r+l,r+a,t.parser.parseInline(e.slice(l,a),r+l)))};for(let f=i;f<e.length;f++){let u=e.charCodeAt(f);u==124&&!h?((!o||l>-1)&&s++,o=!1,n&&(l>-1&&c(),n.push(t.elt("TableDelimiter",f+r,f+r+1))),l=a=-1):(h||u!=32&&u!=9)&&(l<0&&(l=f),a=f+1),h=!h&&u==92}return l>-1&&(s++,n&&c()),s}function ly(t,e){for(let i=e;i<t.length;i++){let n=t.charCodeAt(i);if(n==124)return!0;n==92&&i++}return!1}var Ly=/^\|?(\s*:?-+:?\s*\|)+(\s*:?-+:?\s*)?$/,oa=class{constructor(){this.rows=null}nextLine(e,i,n){if(this.rows==null){this.rows=!1;let r;if((i.next==45||i.next==58||i.next==124)&&Ly.test(r=i.text.slice(i.pos))){let s=[];Js(e,n.content,0,s,n.start)==Js(e,r,0)&&(this.rows=[e.elt("TableHeader",n.start,n.start+n.content.length,s),e.elt("TableDelimiter",e.lineStart+i.pos,e.lineStart+i.text.length)])}}else if(this.rows){let r=[];Js(e,i.text,i.pos,r,e.lineStart),this.rows.push(e.elt("TableRow",e.lineStart+i.pos,e.lineStart+i.text.length,r))}return!1}finish(e,i){return this.rows?(e.addLeafElement(i,e.elt("Table",i.start,i.start+i.content.length,this.rows)),!0):!1}},jT={defineNodes:[{name:"Table",block:!0},{name:"TableHeader",style:{"TableHeader/...":O.heading}},"TableRow",{name:"TableCell",style:O.content},{name:"TableDelimiter",style:O.processingInstruction}],parseBlock:[{name:"Table",leaf(t,e){return ly(e.content,0)?new oa:null},endLeaf(t,e,i){if(i.parsers.some(r=>r instanceof oa)||!ly(e.text,e.basePos))return!1;let n=t.peekLine();return Ly.test(n)&&Js(t,e.text,e.basePos)==Js(t,n,e.basePos)},before:"SetextHeading"}]},Fu=class{nextLine(){return!1}finish(e,i){return e.addLeafElement(i,e.elt("Task",i.start,i.start+i.content.length,[e.elt("TaskMarker",i.start,i.start+3),...e.parser.parseInline(i.content.slice(3),i.start+3)])),!0}},zT={defineNodes:[{name:"Task",block:!0,style:O.list},{name:"TaskMarker",style:O.atom}],parseBlock:[{name: Line truncated
\${}
} catch (\${error}) {
\${}
}`,{label:"try",detail:"/ catch block",type:"keyword"}),A("if (${}) {\n ${}\n}",{label:"if",detail:"block",type:"keyword"}),A(`if (\${}) {
\${}
} else {
\${}
}`,{label:"if",detail:"/ else block",type:"keyword"}),A(`class \${name} {
constructor(\${params}) {
\${}
}
}`,{label:"class",detail:"definition",type:"keyword"}),A('import {${names}} from "${module}"\n${}',{label:"import",detail:"named",type:"keyword"}),A('import ${name} from "${module}"\n${}',{label:"import",detail:"default",type:"keyword"})],BA=k1.concat([A("interface ${name} {\n ${}\n}",{label:"interface",detail:"definition",type:"keyword"}),A("type ${name} = ${type}",{label:"type",detail:"definition",type:"keyword"}),A("enum ${name} {\n ${}\n}",{label:"enum",detail:"definition",type:"keyword"})]),y1=new br,w1=new Set(["Script","Block","FunctionExpression","FunctionDeclaration","ArrowFunction","MethodDeclaration","ForStatement"]);function so(t){return(e,i)=>{let n=e.node.getChild("VariableDefinition");return n&&i(n,t),!0}}var NA=["FunctionDeclaration"],jA={FunctionDeclaration:so("function"),ClassDeclaration:so("class"),ClassExpression:()=>!0,EnumDeclaration:so("constant"),TypeAliasDeclaration:so("type"),NamespaceDeclaration:so("namespace"),VariableDefinition(t,e){t.matchContext(NA)||e(t,"variable")},TypeDefinition(t,e){e(t,"type")},__proto__:null};function v1(t,e){let i=y1.get(e);if(i)return i;let n=[],r=!0;function s(o,l){let a=t.sliceString(o.from,o.to);n.push({label:a,type:l})}return e.cursor(Oe.IncludeAnonymous).iterate(o=>{if(r)r=!1;else if(o.name){let l=jA[o.name];if(l&&l(o,s)||w1.has(o.name))return!1}else if(o.to-o.from>8192){for(let l of v1(t,o.node))n.push(l);return!1}}),y1.set(e,n),n}var S1=/^[\w$\xa1-\uffff][\w$\d\xa1-\uffff]*$/,Q1=["TemplateString","String","RegExp","LineComment","BlockComment","VariableDefinition","TypeDefinition","Label","PropertyDefinition","PropertyName","PrivatePropertyDefinition","PrivatePropertyName","JSXText","JSXAttributeValue","JSXOpenTag","JSXCloseTag","JSXSelfClosingTag",".","?."];function zA(t){let e=he(t.state).resolveInner(t.pos,-1);if(Q1.indexOf(e.name)>-1)return null;let i=e.name=="VariableName"||e.to-e.from<20&&S1.test(t.state.sliceDoc(e.from,e.to));if(!i&&!t.explicit)return null;let n=[];for(let r=e;r;r=r.parent)w1.has(r.name)&&(n=n.concat(v1(t.state.doc,r)));return{options:n,from:i?e.from:t.pos,validFor:S1}}var Ut=Yt.define({name:"javascript",parser:b1.configure({props:[Et.add({IfStatement:kr({except:/^\s*({|else\b)/}),TryStatement:kr({except:/^\s*({|catch\b|finally\b)/}),LabeledStatement:a0,SwitchBody:t=>{let e=t.textAfter,i=/^\s*\}/.test(e),n=/^\s*(case|default)\b/.test(e);return t.baseIndent+(i?0:n?1:2)*t.unit},Block:Zs({closing:"}"}),ArrowFunction:t=>t.baseIndent+t.unit,"TemplateString BlockComment":()=>null,"Statement Property":kr({except:/^\s*{/}),JSXElement(t){let e=/^\s*<\//.test(t.textAfter);return t.lineIndent(t.node.from)+(e?0:t.unit)},JSXEscape(t){let e=/\s*\}/.test(t.textAfter);return t.lineIndent(t.node.from)+(e?0:t.unit)},"JSXOpenTag JSXSelfClosingTag"(t){return t.column(t.node.from)+t.unit}}),Mt.add({"Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression ObjectType":wr,BlockComment(t){return{from:t.from+2,to:t.to-2}},JSXElement(t){let e=t.firstChild;if(!e||e.name=="JSXSelfClosingTag")return null;let i=t.lastChild;return{from:e.to,to:i.type.isError?t.to:i.from}},"JSXSelfClosingTag JSXOpenTag"(t){var e;let i=(e=t.firstChild)===null||e===void 0?void 0:e.nextSibling,n=t.lastChild;return!i||i.type.isError?null:{from:i.to,to:n.type.isError?t.to:n.from}}})]}),languageData:{closeBrackets:{brackets:["(","[","{","'",'"',"`"]},commentTokens:{line:"//",block:{open:"/*",close:"*/"}},indentOnInput:/^\s*(?:case |default:|\{|\}|<\/)$/,wordChars:"$"}}),P1={test:t=>/^JSX/.test(t.name),facet:Sr({commentTokens:{block:{open:"{/*",close:"*/}"}}})},pd=Ut.configure({dialect:"ts"},"typescript"),gd=Ut.configure({dialect:"jsx",props:[Al.add(t=>t.isTop?[P1]:void 0)]}),Od=Ut.configure({dialect:"jsx ts",props:[Al.add(t=>t.isTop?[P1]:void 0)]},"typescript"),$1=t=>({label:t,type:"keyword"}),T1="break case const continue default delete export extends false finally in instanceof let new return static super switch this throw true typeof var yield".split(" ").map($1),YA=T1.concat(["declare","implements","private","protected","public"].map($1));function C1(t={}){let e=t.jsx?t.typescript?Od:gd:t.typescript?pd:Ut,i=t.typescript?BA.concat(YA):k1.concat(T1);return new Qt(e,[Ut.data.of({autocomplete:_b(Q1,bu(i))}),Ut.data.of({autocomplete:zA}),t.jsx?VA:[]])}function qA(t){for(;;){if(t.name=="JSXOpenTag"||t.name=="JSXSelfClosingTag"||t.name=="JSXFragmentTag")return t;if(t.name=="JSXEscape"||!t.parent)return null;t=t.parent}}function x1(t,e,i=t.length){for(let n=e==null?void 0:e.firstChild;n;n=n.nextSibling)if(n.name=="JSXIdentifier"||n.name=="JSXBuiltin"||n.name=="JSXNamespacedName"||n.name=="JSXMemberExpression")return t.sliceString(n.from,Math.min(n.to,i));return""}var WA=typeof navigator=="object"&&/Android\b/.test(navigator.userAgent),VA=T.inputHandler.of((t,e,i,n,r)=>{if((WA?t.composing:t.compositionStarted)||t.state.readOnly||e!=i||n!=">"&&n!="/"||!Ut.isActiveAt(t.state,e,-1))return!1;let s=r(),{state:o}=s,l=o.changeByRange(a=>{var h;let{head:c}=a,f=he(o).resolveInn Line truncated
${a}`}let f=Ed(t.buffer,r[l],s[l],t.position,c);a+=`${" ".repeat(i.indent)}${Md((t.line+1).toString(),h)} | ${f.str}
`,a+=`${"-".repeat(i.indent+h+3+f.pos)}^
`;for(let u=1;u<=i.linesAfter&&!(l+u>=s.length);u++){let d=Ed(t.buffer,r[l+u],s[l+u],t.position-(r[l]-r[l+u]),c);a+=`${" ".repeat(i.indent)}${Md((t.line+u+1).toString(),h)} | ${d.str}
`}return a.replace(/\n$/,"")}function bS(t,e){let i="";return t.mark?(t.mark.name&&(i+=`in "${t.mark.name}" `),i+=`(${t.mark.line+1}:${t.mark.column+1})`,!e&&t.mark.snippet&&(i+=`
${t.mark.snippet}`),`${t.reason} ${i}`):t.reason}var CS=class extends Error{constructor(e,i){super();J(this,"reason");J(this,"mark");this.name="YAMLException",this.reason=e,this.mark=i,this.message=bS(this,!1),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}toString(e){return`${this.name}: ${bS(this,e)}`}};function Pa(t,e,i,n=""){let r=0,s=0;for(let l=0;l<e;l++){let a=t.charCodeAt(l);a===10?(r++,s=l+1):a===13&&(r++,t.charCodeAt(l+1)===10&&l++,s=l+1)}let o={name:n,buffer:t,position:e,line:r,column:e-s};throw o.snippet=X2(o),new CS(i,o)}var _2=-1;function yS(t){switch(t){case 48:return"\0";case 97:return"\x07";case 98:return"\b";case 116:return" ";case 9:return" ";case 110:return`
`;case 118:return"\v";case 102:return"\f";case 114:return"\r";case 101:return"\x1B";case 32:return" ";case 34:return'"';case 47:return"/";case 92:return"\\";case 78:return"\x85";case 95:return"\xA0";case 76:return"\u2028";case 80:return"\u2029";default:return""}}var AS=new Array(256),RS=new Array(256);for(let t=0;t<256;t++)AS[t]=yS(t)?1:0,RS[t]=yS(t);function Z2(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}function D2(t){return t>=48&&t<=57?t-48:(t|32)-97+10}function I2(t){return t===120?2:t===117?4:8}function Sa(t,e,i){let n=0;for(;e<i;){let r=t.charCodeAt(e);if(r===10)n++,e++;else if(r===13)n++,e++,t.charCodeAt(e)===10&&e++;else if(r===32||r===9)e++;else break}return{position:e,breaks:n}}function Wd(t){return t===1?" ":`
`.repeat(t-1)}function B2(t,e,i){let n="",r=e,s=e,o=e;for(;r<i;){let l=t.charCodeAt(r);if(l===10||l===13){n+=t.slice(s,o);let a=Sa(t,r,i);n+=Wd(a.breaks),r=s=o=a.position}else r++,l!==32&&l!==9&&(o=r)}return n+t.slice(s,o)}function N2(t,e,i){let n="",r=e,s=e,o=e;for(;r<i;){let l=t.charCodeAt(r);if(l===39)n+=t.slice(s,r)+"'",r+=2,s=o=r;else if(l===10||l===13){n+=t.slice(s,o);let a=Sa(t,r,i);n+=Wd(a.breaks),r=s=o=a.position}else r++,l!==32&&l!==9&&(o=r)}return n+t.slice(s,i)}function j2(t,e,i){let n="",r=e,s=e,o=e;for(;r<i;){let l=t.charCodeAt(r);if(l===92){n+=t.slice(s,r),r++;let a=t.charCodeAt(r);if(a===10||a===13)r=Sa(t,r,i).position;else if(a<256&&AS[a])n+=RS[a],r++;else{let h=I2(a),c=0;for(;h>0;h--){r++;let f=D2(t.charCodeAt(r));c=(c<<4)+f}n+=Z2(c),r++}s=o=r}else if(l===10||l===13){n+=t.slice(s,o);let a=Sa(t,r,i);n+=Wd(a.breaks),r=s=o=a.position}else r++,l!==32&&l!==9&&(o=r)}return n+t.slice(s,i)}function SS(t,e,i,n,r,s){let o=n<0?0:n,l=t.slice(e,i).replace(/\r\n?/g,`
`),a=l===""?[]:(l.endsWith(`
`)?l.slice(0,-1):l).split(`
`),h="",c=!1,f=0,u=!1;for(let d of a){let p=0;for(;p<o&&d.charCodeAt(p)===32;)p++;if(n<0||p>=d.length){f++;continue}let g=d.slice(o),m=g.charCodeAt(0);s?m===32||m===9?(u=!0,h+=`
`.repeat(c?1+f:f)):u?(u=!1,h+=`
`.repeat(f+1)):f===0?c&&(h+=" "):h+=`
`.repeat(f):h+=`
`.repeat(c?1+f:f),h+=g,c=!0,f=0}return r===3?h+=`
`.repeat(c?1+f:f):r!==2&&c&&(h+=`
`),h}function z2(t,e){if(e.valueStart===_2)return"";let{valueStart:i,valueEnd:n}=e;if(e.fast)return t.slice(i,n);switch(e.style){case 2:return N2(t,i,n);case 3:return j2(t,i,n);case 4:return SS(t,i,n,e.indent,e.chomping,!1);case 5:return SS(t,i,n,e.indent,e.chomping,!0);default:return B2(t,i,n)}}var Y2={"!":"!","!!":"tag:yaml.org,2002:"};function ES(t,e){var s,o;if(t.startsWith("!<")&&t.endsWith(">"))return decodeURIComponent(t.slice(2,-1));let i=t.indexOf("!",1),n=i===-1?"!":t.slice(0,i+1),r=(o=(s=e==null?void 0:e[n])!=null?s:Y2[n])!=null?o:n;return decodeURIComponent(r)+decodeURIComponent(t.slice(n.length))}var Zr=-1,Vd={filename:"",schema:M2,json:!1,maxTotalMergeKeys:1e4,maxAliases:-1};function q2(t){return"tagStart"in t&&t.tagStart!==Zr?t.tagStart:"anchorStart"in t&&t.anchorStart!==Zr?t.anchorStart:"valueStart"in t&&t.valueStart!==Zr?t.valueStart:"start"in t?t.start:0}function St(t,e){Pa(t.source,t.position,e,t.filename)}function MS(t,e,i,n){try{return i.finalize(n)}catch(r){if(r instanceof CS)throw r;Pa(t.source,e,r instanceof Error?r.message:String(r),t.filename)}}function ya(t,e,i){let n=t[i];if(n)return n;for(let r of e)if(i.startsWith(r.tagName))return r}function W2(t,e,i,n,r){let s=ya(e,i,n);if(s)return s;St(t,`unknown ${r} tag !<${n}>`)}function V2(t,e){var s,o;let i=z2(t.source,e),n=e.tagStart===Zr?"":t.source.slice(e.tagStart,e.tagEnd),r=t.schema.defaultScalarTag;if(n!==""){if(n==="!")return{value:i,tag:r};let l=ES(n,t.tagHandlers),a=ya(t.schema.exact.scalar,t.schema.prefix.scalar,l);if(a){let c=a.resolve(i,!0,l);return c===ae&&St(t,`cannot resolve a node with !<${l}> explicit tag`),{value:c,tag:a}}let h=(s=ya(t.schema.exact.mapping,t.schema.prefix.mapping,l))!=null?s:ya(t.schema.exact.sequence,t.schema.prefix.sequence,l);if(h){i!==""&&St(t,`cannot resolve a node with !<${l}> explicit tag`);let c=h.create(l);return{value:h.carrierIsResult?c:MS(t,t.position,h,c),tag:h}}St(t,`unknown scalar tag !<${l}>`)}if(e.style===1){let l=(o=t.schema.implicitScalarByFirstChar.get(i.charAt(0)))!=null?o:t.schema.implicitScalarAnyFirstChar;for(let a of l){let h=a.resolve(i,!1,a.tagName);if(h!==ae)return{value:h,tag:a}}}return{value:r.resolve(i,!1,r.tagName),tag:r}}function xS(t,e,i,n,r,s){let o=e.tagStart===Zr?"":t.source.slice(e.tagStart,e.tagEnd),l=o===""||o==="!"?r:ES(o,t.tagHandlers);return{tagName:l,tag:W2(t,i,n,l,s)}}function LS(t){return t.nodeKind==="mapping"}function kS(t,e,i,n){var r;for(let s of n.keys(i)){if(t.maxTotalMergeKeys!==-1&&++t.totalMergeKeys>t.maxTotalMergeKeys&&St(t,`merge keys exceeded maxTotalMergeKeys (${t.maxTotalMergeKeys})`),e.tag.has(e.value,s))continue;let o=e.tag.addPair(e.value,s,n.get(i,s));o&&St(t,o),((r=e.overridable)!=null?r:e.overridable=new Set).add(s)}}function G2(t,e,i,n){if(t.position=e.keyPosition,LS(n))kS(t,e,i,n);else if(n.nodeKind==="sequence"&&Array.isArray(i))for(let r of i)kS(t,e,r,e.tag);else St(t,"cannot merge mappings; the provided source object is unacceptable")}function U2(t,e,i,n,r){var o,l;if(t.position=e.keyPosition,i===jd){G2(t,e,n,r);return}!t.json&&e.tag.has(e.value,i)&&!((o=e.overridable)!=null&&o.has(i))&&St(t,"duplicated mapping key");let s=e.tag.addPair(e.value,i,n);s&&St(t,s),(l=e.overridable)==null||l.delete(i)}function Ld(t,e,i){let n=t.frames[t.frames.length-1];if(n.kind==="document")n.value=e,n.hasValue=!0;else if(n.kind==="sequence"){n.merge&&(LS(i)||St(t,"cannot merge mappings; the provided source object is unacceptable"));let r=n.tag.addItem(n.value,e,n.index++);r&&St(t,r)}else if(n.hasKey){let r=n.key;n.key=void 0,n.hasKey=!1,U2(t,n,r,e,i)}else n.key=e,n.keyPosition=t.position,n.hasKey=!0}function Xd(t,e,i,n,r){if(e.anchorStart!==Zr){let s={value:i,tag:n,isValueFinal:r};return t.anchors.set(t.source.slice(e.anchorStart,e.anchorEnd),s),s}return null}function F2(t,e){let i={...Vd,...e,events:t,documents:[],eventIndex:0,position:0,frames:[],anchors:new Map,tagHandlers:Object.create(null),totalMergeKeys:0,aliasCount:0};for(;i.eventIndex<i.events.length;){let n=i.events[i.eventIndex++];switch(i.position=q2(n),n.type){case 1:i.anchors=new Map,i.aliasCount=0,i.tagHandlers=Object.create(null);for(let r of n.directives)r.kind==="tag"&&(i.tagHandlers[r.handle]=r.prefix);i.frames.push({kind:"document",position:i.position,value:void 0,hasValue:!1});break;case 4:{let{value:r,tag:s}=V2(i,n);Xd(i,n,r,s,!0),Ld(i,r,s);break}case 2:{let r=xS(i,n,i.schema.exact.sequence,i.schema.prefix.sequence,"tag:yaml.org,2002:seq","sequence"),s=r.tag.create(r.tagName),o=Xd(i,n,s,r.tag,r.tag.carrierIsResult),l=i.frames[i.frames.length-1],a=l!==void 0&&l.kind==="mapping"&&l.hasKey&&l.key===jd;i.frames.push({kind:"sequence",position:i.position,value:s,tag:r.tag,anchor:o,index:0,merge:a});break}case 3:{let r=xS(i,n,i.schema.exact.mapping,i.schema.prefix.mapping,"tag:yaml.org,2002:map","mapping"),s=r.tag.create(r.tagName),o=Xd(i,n,s,r.tag,r.tag.carrierIsResult);i.frames.push({kind:"mapping",position:i.position,value:s,tag:r.tag,anchor:o,key:void 0,keyPosition:i.position,hasK Line truncated
`:n=="r"?"\r":n=="t"?" ":"\\")}eq(e){return this.search==e.search&&this.replace==e.replace&&this.caseSensitive==e.caseSensitive&&this.regexp==e.regexp&&this.wholeWord==e.wholeWord}create(){return this.regexp?new Kd(this):new Hd(this)}getCursor(e,i=0,n){let r=e.doc?e:ce.create({doc:e});return n==null&&(n=r.doc.length),this.regexp?Nr(this,r,i,n):Br(this,r,i,n)}},Xa=class{constructor(e){this.spec=e}};function Br(t,e,i,n){return new tn(e.doc,t.unquoted,i,n,t.caseSensitive?void 0:r=>r.toLowerCase(),t.wholeWord?_E(e.doc,e.charCategorizer(e.selection.main.head)):void 0)}function _E(t,e){return(i,n,r,s)=>((s>i||s+r.length<n)&&(s=Math.max(0,i-2),r=t.sliceString(s,Math.min(t.length,n+2))),(e(_a(r,i-s))!=xe.Word||e(Za(r,i-s))!=xe.Word)&&(e(Za(r,n-s))!=xe.Word||e(_a(r,n-s))!=xe.Word))}var Hd=class extends Xa{constructor(e){super(e)}nextMatch(e,i,n){let r=Br(this.spec,e,n,e.doc.length).nextOverlapping();if(r.done){let s=Math.min(e.doc.length,i+this.spec.unquoted.length);r=Br(this.spec,e,0,s).nextOverlapping()}return r.done||r.value.from==i&&r.value.to==n?null:r.value}prevMatchInRange(e,i,n){for(let r=n;;){let s=Math.max(i,r-1e4-this.spec.unquoted.length),o=Br(this.spec,e,s,r),l=null;for(;!o.nextOverlapping().done;)l=o.value;if(l)return l;if(s==i)return null;r-=1e4}}prevMatch(e,i,n){let r=this.prevMatchInRange(e,0,i);return r||(r=this.prevMatchInRange(e,Math.max(0,n-this.spec.unquoted.length),e.doc.length)),r&&(r.from!=i||r.to!=n)?r:null}getReplacement(e){return this.spec.unquote(this.spec.replace)}matchAll(e,i){let n=Br(this.spec,e,0,e.doc.length),r=[];for(;!n.next().done;){if(r.length>=i)return null;r.push(n.value)}return r}highlight(e,i,n,r){let s=Br(this.spec,e,Math.max(0,i-this.spec.unquoted.length),Math.min(n+this.spec.unquoted.length,e.doc.length));for(;!s.next().done;)r(s.value.from,s.value.to)}};function Nr(t,e,i,n){return new Ca(e.doc,t.search,{ignoreCase:!t.caseSensitive,test:t.wholeWord?ZE(e.charCategorizer(e.selection.main.head)):void 0},i,n)}function _a(t,e){return t.slice(Xe(t,e,!1),e)}function Za(t,e){return t.slice(e,Xe(t,e))}function ZE(t){return(e,i,n)=>!n[0].length||(t(_a(n.input,n.index))!=xe.Word||t(Za(n.input,n.index))!=xe.Word)&&(t(Za(n.input,n.index+n[0].length))!=xe.Word||t(_a(n.input,n.index+n[0].length))!=xe.Word)}var Kd=class extends Xa{nextMatch(e,i,n){let r=Nr(this.spec,e,n,e.doc.length).next();return r.done&&(r=Nr(this.spec,e,0,i).next()),r.done?null:r.value}prevMatchInRange(e,i,n){for(let r=1;;r++){let s=Math.max(i,n-r*1e4),o=Nr(this.spec,e,s,n),l=null;for(;!o.next().done;)l=o.value;if(l&&(s==i||l.from>s+10))return l;if(s==i)return null}}prevMatch(e,i,n){return this.prevMatchInRange(e,0,i)||this.prevMatchInRange(e,n,e.doc.length)}getReplacement(e){return this.spec.unquote(this.spec.replace).replace(/\$([$&\d+])/g,(i,n)=>n=="$"?"$":n=="&"?e.match[0]:n!="0"&&+n<e.match.length?e.match[n]:i)}matchAll(e,i){let n=Nr(this.spec,e,0,e.doc.length),r=[];for(;!n.next().done;){if(r.length>=i)return null;r.push(n.value)}return r}highlight(e,i,n,r){let s=Nr(this.spec,e,Math.max(0,i-250),Math.min(n+250,e.doc.length));for(;!s.next().done;)r(s.value.from,s.value.to)}},fo=q.define(),sp=q.define(),en=pe.define({create(t){return new ho(Jd(t).create(),null)},update(t,e){for(let i of e.effects)i.is(fo)?t=new ho(i.value.create(),t.panel):i.is(sp)&&(t=new ho(t.query,i.value?op:null));return t},provide:t=>mn.from(t,e=>e.panel)});var ho=class{constructor(e,i){this.query=e,this.panel=i}},DE=E.mark({class:"cm-searchMatch"}),IE=E.mark({class:"cm-searchMatch cm-searchMatch-selected"}),BE=Se.fromClass(class{constructor(t){this.view=t,this.decorations=this.highlight(t.state.field(en))}update(t){let e=t.state.field(en);(e!=t.startState.field(en)||t.docChanged||t.selectionSet||t.viewportChanged)&&(this.decorations=this.highlight(e))}highlight({query:t,panel:e}){if(!e||!t.spec.valid)return E.none;let{view:i}=this,n=new Ee;for(let r=0,s=i.visibleRanges,o=s.length;r<o;r++){let{from:l,to:a}=s[r];for(;r<o-1&&a>s[r+1].from-500;)a=s[++r].to;t.highlight(i.state,l,a,(h,c)=>{let f=i.state.selection.ranges.some(u=>u.from==h&&u.to==c);n.add(h,c,f?IE:DE)})}return n.finish()}},{decorations:t=>t.decorations});function uo(t){return e=>{let i=e.state.field(en,!1);return i&&i.query.spec.valid?t(e,i):FS(e)}}var Da=uo((t,{query:e})=>{let{to:i}=t.state.selection.main,n=e.nextMatch(t.state,i,i);if(!n)return!1;let r=v.single(n.from,n.to),s=t.state.facet(Zn);return t.dispatch({selection:r,effects:[ap(t,n),s.scrollToMatch(r.main,t)],userEvent:"select.search"}),US(t),!0}),Ia=uo((t,{query:e})=>{let{state:i}=t,{from:n}=i.selection.main,r=e.prevMatch(i,n,n);if(!r)return!1;let s=v.single(r.from,r.to),o=t.state.facet(Zn);return t.dispatch({selection:s,effects:[ap(t,r),o.scrollToMatch(s.main,t)],userEvent:"select.search"}),US(t),!0}),NE=uo((t,{query:e})=>{let i=e.matchAll(t.state,1e3);return!i||!i.length?!1:(t.dispatch({selection:v.create(i.map(n=>v.range(n.from,n.to))),userEvent:"select.search.matches"}),!0)}),jE=({state:t,dispatch:e})=>{let i=t.select Line truncated
]`).replace("lheading",Gx).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},qM=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,WM=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,Fx=/^( {2,}|\\)\n(?!\s*$)/,VM=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,Hr=/[\p{P}\p{S}]/u,nc=/[\s\p{P}\p{S}]/u,Hp=/[^\s\p{P}\p{S}]/u,GM=oe(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,nc).getRegex(),Hx=/(?!~)[\p{P}\p{S}]/u,UM=/(?!~)[\s\p{P}\p{S}]/u,FM=/(?:[^\s\p{P}\p{S}]|~)/u,HM=oe(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",EM?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),Kx=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,KM=oe(Kx,"u").replace(/punct/g,Hr).getRegex(),JM=oe(Kx,"u").replace(/punct/g,Hx).getRegex(),Jx="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",eL=oe(Jx,"gu").replace(/notPunctSpace/g,Hp).replace(/punctSpace/g,nc).replace(/punct/g,Hr).getRegex(),tL=oe(Jx,"gu").replace(/notPunctSpace/g,FM).replace(/punctSpace/g,UM).replace(/punct/g,Hx).getRegex(),iL=oe("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,Hp).replace(/punctSpace/g,nc).replace(/punct/g,Hr).getRegex(),nL=oe(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,Hr).getRegex(),rL="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",sL=oe(rL,"gu").replace(/notPunctSpace/g,Hp).replace(/punctSpace/g,nc).replace(/punct/g,Hr).getRegex(),oL=oe(/\\(punct)/,"gu").replace(/punct/g,Hr).getRegex(),lL=oe(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),aL=oe(Up).replace("(?:-->|$)","-->").getRegex(),cL=oe("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",aL).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),Ja=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,hL=oe(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",Ja).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ek=oe(/^!?\[(label)\]\[(ref)\]/).replace("label",Ja).replace("ref",Gp).getRegex(),tk=oe(/^!?\[(ref)\](?:\[\])?/).replace("ref",Gp).getRegex(),fL=oe("reflink|nolink(?!\\()","g").replace("reflink",ek).replace("nolink",tk).getRegex(),Bx=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,Kp={_backpedal:Gn,anyPunctuation:oL,autolink:lL,blockSkip:HM,br:Fx,code:WM,del:Gn,delLDelim:Gn,delRDelim:Gn,emStrongLDelim:KM,emStrongRDelimAst:eL,emStrongRDelimUnd:iL,escape:qM,link:hL,nolink:tk,punctuation:GM,reflink:ek,reflinkSearch:fL,tag:cL,text:VM,url:Gn},uL={...Kp,link:oe(/^!?\[(label)\]\((.*?)\)/).replace("label",Ja).getRegex(),reflink:oe(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",Ja).getRegex()},jp={...Kp,emStrongRDelimAst:tL,emStrongLDelim:JM,delLDelim:nL,delRDelim:sL,url:oe(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",Bx).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:oe(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",Bx).getRegex()},dL={...jp,br:oe(Fx).replace("{2,}","*").getRegex(),text:oe(jp.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},Ha={normal:Fp,gfm:zM,pedantic:YM},xo={normal:Kp,gfm:jp,breaks:dL,pedantic:uL},pL={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},Nx=t=>pL[t];function mi(t,e){if(e){if(nt.escapeTest.test(t))return t.replace(nt.escapeReplace,Nx)}else if(nt.escapeTestNoEncode.tesLine truncated
`),i=e.length-1;for(;i>=0&&nt.blankLine.test(e[i]);)i--;return e.length-i<=2?t:e.slice(0,i+1).join(`
`)}function gL(t,e){if(t.indexOf(e[1])===-1)return-1;let i=0;for(let n=0;n<t.length;n++)if(t[n]==="\\")n++;else if(t[n]===e[0])i++;else if(t[n]===e[1]&&(i--,i<0))return n;return i>0?-2:-1}function OL(t,e=0){let i=e,n="";for(let r of t)if(r===" "){let s=4-i%4;n+=" ".repeat(s),i+=s}else n+=r,i++;return n}function qx(t,e,i,n,r){let s=e.href,o=e.title||null,l=t[1].replace(r.other.outputLinkReplace,"$1");n.state.inLink=!0;let a={type:t[0].charAt(0)==="!"?"image":"link",raw:i,href:s,title:o,text:l,tokens:n.inlineTokens(l)};return n.state.inLink=!1,a}function mL(t,e,i){let n=t.match(i.other.indentCodeCompensation);if(n===null)return e;let r=n[1];return e.split(`
`).map(s=>{let o=s.match(i.other.beginningSpace);if(o===null)return s;let[l]=o;return l.length>=r.length?s.slice(r.length):s}).join(`
`)}var ec=class{constructor(t){J(this,"options");J(this,"rules");J(this,"lexer");this.options=t||Fn}space(t){let e=this.rules.block.newline.exec(t);if(e&&e[0].length>0)return{type:"space",raw:e[0]}}code(t){let e=this.rules.block.code.exec(t);if(e){let i=this.options.pedantic?e[0]:Yx(e[0]),n=i.replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:i,codeBlockStyle:"indented",text:n}}}fences(t){let e=this.rules.block.fences.exec(t);if(e){let i=e[0],n=mL(i,e[3]||"",this.rules);return{type:"code",raw:i,lang:e[2]?e[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):e[2],text:n}}}heading(t){let e=this.rules.block.heading.exec(t);if(e){let i=e[2].trim();if(this.rules.other.endingHash.test(i)){let n=sn(i,"#");(this.options.pedantic||!n||this.rules.other.endingSpaceChar.test(n))&&(i=n.trim())}return{type:"heading",raw:sn(e[0],`
`),depth:e[1].length,text:i,tokens:this.lexer.inline(i)}}}hr(t){let e=this.rules.block.hr.exec(t);if(e)return{type:"hr",raw:sn(e[0],`
`)}}blockquote(t){let e=this.rules.block.blockquote.exec(t);if(e){let i=sn(e[0],`
`).split(`
`),n="",r="",s=[];for(;i.length>0;){let o=!1,l=[],a;for(a=0;a<i.length;a++)if(this.rules.other.blockquoteStart.test(i[a]))l.push(i[a]),o=!0;else if(!o)l.push(i[a]);else break;i=i.slice(a);let h=l.join(`
`),c=h.replace(this.rules.other.blockquoteSetextReplace,`
$1`).replace(this.rules.other.blockquoteSetextReplace2,"");n=n?`${n}
${h}`:h,r=r?`${r}
${c}`:c;let f=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(c,s,!0),this.lexer.state.top=f,i.length===0)break;let u=s.at(-1);if((u==null?void 0:u.type)==="code")break;if((u==null?void 0:u.type)==="blockquote"){let d=u,p=d.raw+`
`+i.join(`
`),g=this.blockquote(p);s[s.length-1]=g,n=n.substring(0,n.length-d.raw.length)+g.raw,r=r.substring(0,r.length-d.text.length)+g.text;break}else if((u==null?void 0:u.type)==="list"){let d=u,p=d.raw+`
`+i.join(`
`),g=this.list(p);s[s.length-1]=g,n=n.substring(0,n.length-u.raw.length)+g.raw,r=r.substring(0,r.length-d.raw.length)+g.raw,i=p.substring(s.at(-1).raw.length).split(`
`);continue}}return{type:"blockquote",raw:n,tokens:s,text:r}}}list(t){let e=this.rules.block.list.exec(t);if(e){let i=e[1].trim(),n=i.length>1,r={type:"list",raw:"",ordered:n,start:n?+i.slice(0,-1):"",loose:!1,items:[]};i=n?`\\d{1,9}\\${i.slice(-1)}`:`\\${i}`,this.options.pedantic&&(i=n?i:"[*+-]");let s=this.rules.other.listItemRegex(i),o=!1;for(;t;){let a=!1,h="",c="";if(!(e=s.exec(t))||this.rules.block.hr.test(t))break;h=e[0],t=t.substring(h.length);let f=OL(e[2].split(`
`,1)[0],e[1].length),u=t.split(`
`,1)[0],d=!f.trim(),p=0;if(this.options.pedantic?(p=2,c=f.trimStart()):d?p=e[1].length+1:(p=f.search(this.rules.other.nonSpaceChar),p=p>4?1:p,c=f.slice(p),p+=e[1].length),d&&this.rules.other.blankLine.test(u)&&(h+=u+`
`,t=t.substring(u.length+1),a=!0),!a){let g=this.rules.other.nextBulletRegex(p),m=this.rules.other.hrRegex(p),b=this.rules.other.fencesBeginRegex(p),y=this.rules.other.headingBeginRegex(p),x=this.rules.other.htmlBeginRegex(p),Q=this.rules.other.blockquoteBeginRegex(p);for(;t;){let S=t.split(`
`,1)[0],k;if(u=S,this.options.pedantic?(u=u.replace(this.rules.other.listReplaceNesting," "),k=u):k=u.replace(this.rules.other.tabCharGlobal," "),b.test(u)||y.test(u)||x.test(u)||Q.test(u)||g.test(u)||m.test(u))break;if(k.search(this.rules.other.nonSpaceChar)>=p||!u.trim())c+=`
`+k.slice(p);else{if(d||f.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||b.test(f)||y.test(f)||m.test(f))break;c+=`
`+u}d=!u.trim(),h+=S+`
`,t=t.substring(S.length+1),f=k.slice(p)}}r.loose||(o?r.loose=!0:this.rules.other.doubleBlankLine.test(h)&&(o=!0)),r.items.push({type:"list_item",raw:h,task:!!this.options.gfm&&this.rules.other.listIsTask.test(c),loose:!1,text:c,tokens:[]}),r.raw+=h}let l=r.items.at(-1);if(l)l.raw=l.raw.trimEnd(),l.text=l.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){this.lexer.state.top=!1,a.tokens=this.lexer.blockTokens(a.text,[]);let h=a.tokens[0];if(a.task&&((h==null?void 0:h.type)==="text"||(h==null?void 0:h.type)==="paragraph")){a.text=a.text.replace(this.rules.other.listReplaceTask,""),h.raw=h.raw.replace(this.rules.other.listReplaceTask,""),h.text=h.text.replace(this.rules.other.listReplaceTask,"");for(let f=this.lexer.inlineQueue.length-1;f>=0;f--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[f].src)){this.lexer.inlineQueue[f].src=this.lexer.inlineQueue[f].src.replace(this.rules.other.listReplaceTask,"");break}let c=this.rules.other.listTaskCheckbox.exec(a.raw);if(c){let f={type:"checkbox",raw:c[0]+" ",checked:c[0]!=="[ ]"};a.checked=f.checked,r.loose?a.tokens[0]&&["paragraph","text"].includes(a.tokens[0].type)&&"tokens"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=f.raw+a.tokens[0].raw,a.tokens[0].text=f.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(f)):a.tokens.unshift({type:"paragraph",raw:f.raw,text:f.raw,tokens:[f]}):a.tokens.unshift(f)}}else a.task&&(a.task=!1);if(!r.loose){let c=a.tokens.filter(u=>u.type==="space"),f=c.length>0&&c.some(u=>this.rules.other.anyLine.test(u.raw));r.loose=f}}if(r.loose)for(let a of r.items){a.loose=!0;for(let h of a.tokens)h.type==="text"&&(h.type="paragraph")}return r}}html(t){let e=this.rules.block.html.exec(t);if(e){let i=Yx(e[0]);return{type:"html",block:!0,raw:i,pre:e[1]==="pre"||e[1]==="script"||e[1]==="style",text:i}}}def(t){let e=this.rules.block.def.exec(t);if(e){let i=e[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),n=e[2]?e[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=e[3]?e[3].substring(1,e[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):e[3];return{type:"def",tag:i,raw:sn(e[0],`
`),href:n,title:r}}}table(t){var o;let e=this.rules.block.table.exec(t);if(!e||!this.rules.other.tableDelimiter.test(e[2]))return;let i=zx(e[1]),n=e[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=(o=e[3])!=null&&o.trim()?e[3].replace(this.rules.other.tableRowBlankLine,"").split(`
`):[],s={type:"table",raw:sn(e[0],`
`),header:[],align:[],rows:[]};if(i.length===n.length){for(let l of n)this.rules.other.tableAlignRight.test(l)?s.align.push("right"):this.rules.other.tableAlignCenter.test(l)?s.align.push("center"):this.rules.other.tableAlignLeft.test(l)?s.align.push("left"):s.align.push(null);for(let l=0;l<i.length;l++)s.header.push({text:i[l],tokens:this.lexer.inline(i[l]),header:!0,align:s.align[l]});for(let l of r)s.rows.push(zx(l,s.header.length).map((a,h)=>({text:a,tokens:this.lexer.inline(a),header:!1,align:s.align[h]})));return s}}lheading(t){let e=this.rules.block.lheading.exec(t);if(e){let i=e[1].trim();return{type:"heading",raw:sn(e[0],`
`),depth:e[2].charAt(0)==="="?1:2,text:i,tokens:this.lexer.inline(i)}}}paragraph(t){let e=this.rules.block.paragraph.exec(t);if(e){let i=e[1].charAt(e[1].length-1)===`
`?e[1].slice(0,-1):e[1];return{type:"paragraph",raw:e[0],text:i,tokens:this.lexer.inline(i)}}}text(t){let e=this.rules.block.text.exec(t);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(t){let e=this.rules.inline.escape.exec(t);if(e)return{type:"escape",raw:e[0],text:e[1]}}tag(t){let e=this.rules.inline.tag.exec(t);if(e)return!this.lexer.state.inLink&&this.rules.other.startATag.test(e[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(t){let e=this.rules.inline.link.exec(t);if(e){let i=e[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(i)){if(!this.rules.other.endAngleBracket.test(i))return;let s=sn(i.slice(0,-1),"\\");if((i.length-s.length)%2===0)return}else{let s=gL(e[2],"()");if(s===-2)return;if(s>-1){let o=(e[0].indexOf("!")===0?5:4)+e[1].length+s;e[2]=e[2].substring(0,s),e[0]=e[0].substring(0,o).trim(),e[3]=""}}let n=e[2],r="";if(this.options.pedantic){let s=this.rules.other.pedanticHrefTitle.exec(n);s&&(n=s[1],r=s[3])}else r=e[3]?e[3].slice(1,-1):"";return n=n.trim(),this.rules.other.startAngleBracket.test(n)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(i)?n=n.slice(1):n=n.slice(1,-1)),qx(e,{href:n&&n.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},e[0],this.lexer,this.rules)}}reflink(t,e){let i;if((i=this.rules.inline.reflink.exec(t))||(i=this.rules.inline.nolink.exec(t))){let n=(i[2]||i[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=e[n.toLowerCase()];if(!r){let s=i[0].charAt(0);return{type:"text",raw:s,text:s}}return qx(i,r,i[0],this.lexer,this.rules)}}emStrong(t,e,i=""){let n=this.rules.inline.emStrongLDelim.exec(t);if(!(!n||!n[1]&&!n[2]&&!n[3]&&!n[4]||n[4]&&i.match(this.rules.other.unicodeAlphaNumeric))&&(!(n[1]||n[3])||!i||this.rules.inline.punctuation.exec(i))){let r=[...n[0]].length-1,s,o,l=r,a=0,h=n[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(h.lastIndex=0,e=e.slice(-1*t.length+r);(n=h.exec(e))!==null;){if(s=n[1]||n[2]||n[3]||n[4]||n[5]||n[6],!s)continue;if(o=[...s].length,n[3]||n[4]){l+=o;continue}else if((n[5]||n[6])&&r%3&&!((r+o)%3)){a+=o;continue}if(l-=o,l>0)continue;o=Math.min(o,o+l+a);let c=[...n[0]][0].length,f=t.slice(0,r+n.index+c+o);if(Math.min(r,o)%2){let d=f.slice(1,-1);return{type:"em",raw:f,text:d,tokens:this.lexer.inlineTokens(d)}}let u=f.slice(2,-2);return{type:"strong",raw:f,text:u,tokens:this.lexer.inlineTokens(u)}}}}codespan(t){let e=this.rules.inline.code.exec(t);if(e){let i=e[2].replace(this.rules.other.newLineCharGlobal," "),n=this.rules.other.nonSpaceChar.test(i),r=this.rules.other.startingSpaceChar.test(i)&&this.rules.other.endingSpaceChar.test(i);return n&&r&&(i=i.substring(1,i.length-1)),{type:"codespan",raw:e[0],text:i}}}br(t){let e=this.rules.inline.br.exec(t);if(e)return{type:"br",raw:e[0]}}del(t,e,i=""){let n=this.rules.inline.delLDelim.exec(t);if(n&&(!n[1]||!i||this.rules.inline.punctuation.exec(i))){let r=[...n[0]].length-1,s,o,l=r,a=this.rules.inline.delRDelim;for(a.lastIndex=0,e=e.slice(-1*t.length+r);(n=a.exec(e))!==null;){if(s=n[1]||n[2]||n[3]||n[4]||n[5]||n[6],!s||(o=[...s].length,o!==r))continue;if(n[3]||n[4]){l+=o;continue}if(l-=o,l>0)continue;o=Math.min(o,o+l);let h=[...n[0]][0].length,c=t.slice(0,r+n.index+h+o),f=c.slice(r,-r);return{type:"del",raw:c,text:f,tokens:this.lexer.inlineTokens(f)}}}}autolink(t){let e=this.rules.inline.autolink.exec(t);if(e){let i,n;return e[2]==="@"?(i=e[1],n="mailto:"+i):(i=e[1],n=i),{type:"link",raw:e[0],text:i,href:n,tokens:[{type:"text",raw:i,text:i}]}}}url(t){var i,n;let e;if(e=this.rules.inline.url.exec(t)){let r,s;if(e[2]==="@")r=e[0],s="mailto:"+r;else{let o;do o=e[0],e[0]=(n=(i=this.rules.inline._backpedal.exec(e[0]))==null?void 0:i[0])!=null?n:"";while(o!==e[0]);r=e[0],e[1]==="www."?s="http://"+e[0]:s=e[0]}return{type:"link",raw:e[0],text:r,href:s,tokens:[{type:"text",raw:r,text:r}]}}}inlineText(t){let e=this.rules.inline.text.exec(t);if(e){let i=this.lexer.state.inRawBlock;return{type:"text",raw:e[0],text:e[0],escaped:i}}}},Jt=class zp{constructor(e){J(this,"tokens");J(this,"options");J(this,"state");J(this,"inlineQueue");J(this,"tokenizer");this.tokens=[],this.tokens.links=Object.create(null),this.options=e||Fn,this.options.tokenizer=this.options.tokenizer||new ec,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let i={other:nt,block:Ha.normal,inline:xo.normal};this.options.pedantic?(i.block=Ha.pedantic,i.inline=xo.p Line truncated
`),this.blockTokens(e,this.tokens);for(let i=0;i<this.inlineQueue.length;i++){let n=this.inlineQueue[i];this.inlineTokens(n.src,n.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,i=[],n=!1){var s,o,l;this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(nt.tabCharGlobal," ").replace(nt.spaceLine,""));let r=1/0;for(;e;){if(e.length<r)r=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}let a;if((o=(s=this.options.extensions)==null?void 0:s.block)!=null&&o.some(c=>(a=c.call({lexer:this},e,i))?(e=e.substring(a.raw.length),i.push(a),!0):!1))continue;if(a=this.tokenizer.space(e)){e=e.substring(a.raw.length);let c=i.at(-1);a.raw.length===1&&c!==void 0?c.raw+=`
`:i.push(a);continue}if(a=this.tokenizer.code(e)){e=e.substring(a.raw.length);let c=i.at(-1);(c==null?void 0:c.type)==="paragraph"||(c==null?void 0:c.type)==="text"?(c.raw+=(c.raw.endsWith(`
`)?"":`
`)+a.raw,c.text+=`
`+a.text,this.inlineQueue.at(-1).src=c.text):i.push(a);continue}if(a=this.tokenizer.fences(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.heading(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.hr(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.blockquote(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.list(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.html(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.def(e)){e=e.substring(a.raw.length);let c=i.at(-1);(c==null?void 0:c.type)==="paragraph"||(c==null?void 0:c.type)==="text"?(c.raw+=(c.raw.endsWith(`
`)?"":`
`)+a.raw,c.text+=`
`+a.raw,this.inlineQueue.at(-1).src=c.text):this.tokens.links[a.tag]||(this.tokens.links[a.tag]={href:a.href,title:a.title},i.push(a));continue}if(a=this.tokenizer.table(e)){e=e.substring(a.raw.length),i.push(a);continue}if(a=this.tokenizer.lheading(e)){e=e.substring(a.raw.length),i.push(a);continue}let h=e;if((l=this.options.extensions)!=null&&l.startBlock){let c=1/0,f=e.slice(1),u;this.options.extensions.startBlock.forEach(d=>{u=d.call({lexer:this},f),typeof u=="number"&&u>=0&&(c=Math.min(c,u))}),c<1/0&&c>=0&&(h=e.substring(0,c+1))}if(this.state.top&&(a=this.tokenizer.paragraph(h))){let c=i.at(-1);n&&(c==null?void 0:c.type)==="paragraph"?(c.raw+=(c.raw.endsWith(`
`)?"":`
`)+a.raw,c.text+=`
`+a.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=c.text):i.push(a),n=h.length!==e.length,e=e.substring(a.raw.length);continue}if(a=this.tokenizer.text(e)){e=e.substring(a.raw.length);let c=i.at(-1);(c==null?void 0:c.type)==="text"?(c.raw+=(c.raw.endsWith(`
`)?"":`
`)+a.raw,c.text+=`
`+a.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=c.text):i.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=!0,i}inline(e,i=[]){return this.inlineQueue.push({src:e,tokens:i}),i}inlineTokens(e,i=[]){var h,c,f,u,d,p;this.tokenizer.lexer=this;let n=e,r=null;if(this.tokens.links){let g=Object.keys(this.tokens.links);if(g.length>0)for(;(r=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)g.includes(r[0].slice(r[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,r.index)+"["+"a".repeat(r[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(r=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,r.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let s;for(;(r=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)s=r[2]?r[2].length:0,n=n.slice(0,r.index+s)+"["+"a".repeat(r[0].length-s-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=(f=(c=(h=this.options.hooks)==null?void 0:h.emStrongMask)==null?void 0:c.call({lexer:this},n))!=null?f:n;let o=!1,l="",a=1/0;for(;e;){if(e.length<a)a=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}o||(l=""),o=!1;let g;if((d=(u=this.options.extensions)==null?void 0:u.inline)!=null&&d.some(b=>(g=b.call({lexer:this},e,i))?(e=e.substring(g.raw.length),i.push(g),!0):!1))continue;if(g=this.tokenizer.escape(e)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.tag(e)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.link(e)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(g.raw.length);let b=i.at(-1);g.type==="text"&&(b==null?void 0:b.type)==="text"?(b.raw+=g.raw,b.text+=g.text):i.push(g);continue}if(g=this.tokenizer.emStrong(e,n,l)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.codespan(e)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.br(e)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.del(e,n,l)){e=e.substring(g.raw.length),i.push(g);continue}if(g=this.tokenizer.autolink(e)){e=e.substring(g.raw.length),i.push(g);continue}if(!this.state.inLink&&(g=this.tokenizer.url(e))){e=e.substring(g.raw.length),i.push(g);continue}let m=e;if((p=this.options.extensions)!=null&&p.startInline){let b=1/0,y=e.slice(1),x;this.options.extensions.startInline.forEach(Q=>{x=Q.call({lexer:this},y),typeof x=="number"&&x>=0&&(b=Math.min(b,x))}),b<1/0&&b>=0&&(m=e.substring(0,b+1))}if(g=this.tokenizer.inlineText(m)){e=e.substring(g.raw.length),g.raw.slice(-1)!=="_"&&(l=g.raw.slice(-1)),o=!0;let b=i.at(-1);(b==null?void 0:b.type)==="text"?(b.raw+=g.raw,b.text+=g.text):i.push(g);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return i}infiniteLoopError(e){let i="Infinite loop on byte: "+e;if(this.options.silent)console.error(i);else throw new Error(i)}},tc=class{constructor(t){J(this,"options");J(this,"parser");this.options=t||Fn}space(t){return""}code({text:t,lang:e,escaped:i}){var s;let n=(s=(e||"").match(nt.notSpaceStart))==null?void 0:s[0],r=t.replace(nt.endingNewline,"")+`
`;return n?'<pre><code class="language-'+mi(n)+'">'+(i?r:mi(r,!0))+`</code></pre>
`:"<pre><code>"+(i?r:mi(r,!0))+`</code></pre>
`}blockquote({tokens:t}){return`<blockquote>
${this.parser.parse(t)}</blockquote>
`}html({text:t}){return t}def(t){return""}heading({tokens:t,depth:e}){return`<h${e}>${this.parser.parseInline(t)}</h${e}>
`}hr(t){return`<hr>
`}list(t){let e=t.ordered,i=t.start,n="";for(let o=0;o<t.items.length;o++){let l=t.items[o];n+=this.listitem(l)}let r=e?"ol":"ul",s=e&&i!==1?' start="'+i+'"':"";return"<"+r+s+`>
`+n+"</"+r+`>
`}listitem(t){return`<li>${this.parser.parse(t.tokens)}</li>
`}checkbox({checked:t}){return"<input "+(t?'checked="" ':"")+'disabled="" type="checkbox"> '}paragraph({tokens:t}){return`<p>${this.parser.parseInline(t)}</p>
`}table(t){let e="",i="";for(let r=0;r<t.header.length;r++)i+=this.tablecell(t.header[r]);e+=this.tablerow({text:i});let n="";for(let r=0;r<t.rows.length;r++){let s=t.rows[r];i="";for(let o=0;o<s.length;o++)i+=this.tablecell(s[o]);n+=this.tablerow({text:i})}return n&&(n=`<tbody>${n}</tbody>`),`<table>
<thead>
`+e+`</thead>
`+n+`</table>
`}tablerow({text:t}){return`<tr>
${t}</tr>
`}tablecell(t){let e=this.parser.parseInline(t.tokens),i=t.header?"th":"td";return(t.align?`<${i} align="${t.align}">`:`<${i}>`)+e+`</${i}>
`}strong({tokens:t}){return`<strong>${this.parser.parseInline(t)}</strong>`}em({tokens:t}){return`<em>${this.parser.parseInline(t)}</em>`}codespan({text:t}){return`<code>${mi(t,!0)}</code>`}br(t){return"<br>"}del({tokens:t}){return`<del>${this.parser.parseInline(t)}</del>`}link({href:t,title:e,tokens:i}){let n=this.parser.parseInline(i),r=jx(t);if(r===null)return n;t=r;let s='<a href="'+t+'"';return e&&(s+=' title="'+mi(e)+'"'),s+=">"+n+"</a>",s}image({href:t,title:e,text:i,tokens:n}){n&&(i=this.parser.parseInline(n,this.parser.textRenderer));let r=jx(t);if(r===null)return mi(i);t=r;let s=`<img src="${t}" alt="${mi(i)}"`;return e&&(s+=` title="${mi(e)}"`),s+=">",s}text(t){return"tokens"in t&&t.tokens?this.parser.parseInline(t.tokens):"escaped"in t&&t.escaped?t.text:mi(t.text)}},Jp=class{strong({text:t}){return t}em({text:t}){return t}codespan({text:t}){return t}del({text:t}){return t}html({text:t}){return t}text({text:t}){return t}link({text:t}){return""+t}image({text:t}){return""+t}br(){return""}checkbox({raw:t}){return t}},ei=class Yp{constructor(e){J(this,"options");J(this,"renderer");J(this,"textRenderer");this.options=e||Fn,this.options.renderer=this.options.renderer||new tc,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new Jp}static parse(e,i){return new Yp(i).parse(e)}static parseInline(e,i){return new Yp(i).parseInline(e)}parse(e){var n,r;this.renderer.parser=this;let i="";for(let s=0;s<e.length;s++){let o=e[s];if((r=(n=this.options.extensions)==null?void 0:n.renderers)!=null&&r[o.type]){let a=o,h=this.options.extensions.renderers[a.type].call({parser:this},a);if(h!==!1||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(a.type)){i+=h||"";continue}}let l=o;switch(l.type){case"space":{i+=this.renderer.space(l);break}case"hr":{i+=this.renderer.hr(l);break}case"heading":{i+=this.renderer.heading(l);break}case"code":{i+=this.renderer.code(l);break}case"table":{i+=this.renderer.table(l);break}case"blockquote":{i+=this.renderer.blockquote(l);break}case"list":{i+=this.renderer.list(l);break}case"checkbox":{i+=this.renderer.checkbox(l);break}case"html":{i+=this.renderer.html(l);break}case"def":{i+=this.renderer.def(l);break}case"paragraph":{i+=this.renderer.paragraph(l);break}case"text":{i+=this.renderer.text(l);break}default:{let a='Token with "'+l.type+'" type was not found.';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return i}parseInline(e,i=this.renderer){var r,s;this.renderer.parser=this;let n="";for(let o=0;o<e.length;o++){let l=e[o];if((s=(r=this.options.extensions)==null?void 0:r.renderers)!=null&&s[l.type]){let h=this.options.extensions.renderers[l.type].call({parser:this},l);if(h!==!1||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(l.type)){n+=h||"";continue}}let a=l;switch(a.type){case"escape":{n+=i.text(a);break}case"html":{n+=i.html(a);break}case"link":{n+=i.link(a);break}case"image":{n+=i.image(a);break}case"checkbox":{n+=i.checkbox(a);break}case"strong":{n+=i.strong(a);break}case"em":{n+=i.em(a);break}case"codespan":{n+=i.codespan(a);break}case"br":{n+=i.br(a);break}case"del":{n+=i.del(a);break}case"text":{n+=i.text(a);break}default:{let h='Token with "'+a.type+'" type was not found.';if(this.options.silent)return console.error(h),"";throw new Error(h)}}}return n}},Ka,ko=(Ka=class{constructor(t){J(this,"options");J(this,"block");this.options=t||Fn}preprocess(t){return t}postprocess(t){return t}processAllTokens(t){return t}emStrongMask(t){return t}provideLexer(t=this.block){return t?Jt.lex:Jt.lexInline}provideParser(t=this.block){return t?ei.parse:ei.parseInline}},J(Ka,"passThroughHooks",new Set(["preprocess","postprocess","processAllTokens","emStrongMask"])),J(Ka,"passThroughHooksRespectAsync",new Set(["preprocess","postprocess","processAllTokens"])),Ka),bL=class{constructor(...t){J(this,"defaults",qp());J(this,"options",this.setOptions);J(this,"parse",this.parseMarkdown(!0));J(this,"parseInline",this.parseMarkdown(!1));J(this,"Parser",ei);J(this,"Renderer",tc);J(this,"TextRenderer",Jp);J(this,"Lexer",Jt);J(this,"Tokenizer",ec);J(this,"Hooks",ko);this.use(...t)}walkTokens(t,e){var n,r;let i=[];for(let s of t)switch(i=i.concat(e.call(this,s)),s.type){case"table":{let o=s;for(let l of o.header)i=i.concat(this.walkTokens(l.tokens,e));for(let l of o.rows)for(let a of l)i=i.concat(this.walkTokens(a.tokens,e));break}case"list":{let o=s;i=i.concat(this.walkTokens(o.items,e));break}default:{let o=s;(r=(n=this.defaults.extensions)==null?void 0:n.childTokens)!=null&&r[o.type]?this.defaults.extensions.childTokens[o.type].forEach(l=>{let a=o[l].flat(1/0);i=i.concat(this.walkTokens(a,e))}):o.tokens&&(i=i.concat(this.walkTokens(o.tokens,e)))}}return i}use(...t){let e=this.defaults.extensions||{renderers:{},childTokens:{}};return t.forEach(i=>{let n={...i};if(n.async=this.defaults.async||n.async||!1,i.extensions&&(i.extensLine truncated
Please report this to https://github.com/markedjs/marked.`,t){let n="<p>An error occurred:</p><pre>"+mi(i.message+"",!0)+"</pre>";return e?Promise.resolve(n):n}if(e)return Promise.reject(i);throw i}}},Un=new bL;function de(t,e){return Un.parse(t,e)}de.options=de.setOptions=function(t){return Un.setOptions(t),de.defaults=Un.defaults,Wx(de.defaults),de};de.getDefaults=qp;de.defaults=Fn;de.use=function(...t){return Un.use(...t),de.defaults=Un.defaults,Wx(de.defaults),de};de.walkTokens=function(t,e){return Un.walkTokens(t,e)};de.parseInline=Un.parseInline;de.Parser=ei;de.parser=ei.parse;de.Renderer=tc;de.TextRenderer=Jp;de.Lexer=Jt;de.lexer=Jt.lex;de.Tokenizer=ec;de.Hooks=ko;de.parse=de;var gZ=de.options,OZ=de.setOptions,mZ=de.use,bZ=de.walkTokens,yZ=de.parseInline;var SZ=ei.parse,xZ=Jt.lex;var kk=Yk(xk(),1);var Ei=kk.default;function ag(t){let e="true false yes no null",i="[\\w#;/?:@&=+$,.~*'()[\\]]+",n={className:"attr",variants:[{begin:/[\w*@][\w*@ :()\./-]*:(?=[ \t]|$)/},{begin:/"[\w*@][\w*@ :()\./-]*":(?=[ \t]|$)/},{begin:/'[\w*@][\w*@ :()\./-]*':(?=[ \t]|$)/}]},r={className:"template-variable",variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]},s={className:"string",relevance:0,begin:/'/,end:/'/,contains:[{match:/''/,scope:"char.escape",relevance:0}]},o={className:"string",relevance:0,variants:[{begin:/"/,end:/"/},{begin:/\S+/}],contains:[t.BACKSLASH_ESCAPE,r]},l=t.inherit(o,{variants:[{begin:/'/,end:/'/,contains:[{begin:/''/,relevance:0}]},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),u={className:"number",begin:"\\b"+"[0-9]{4}(-[0-9][0-9]){0,2}"+"([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?"+"(\\.[0-9]*)?"+"([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?"+"\\b"},d={end:",",endsWithParent:!0,excludeEnd:!0,keywords:e,relevance:0},p={begin:/\{/,end:/\}/,contains:[d],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[d],illegal:"\\n",relevance:0},m=[n,{className:"meta",begin:"^---\\s*$",relevance:10},{className:"string",begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+i},{className:"type",begin:"!<"+i+">"},{className:"type",begin:"!"+i},{className:"type",begin:"!!"+i},{className:"meta",begin:"&"+t.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+t.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",relevance:0},t.HASH_COMMENT_MODE,{beginKeywords:e,keywords:{literal:e}},u,{className:"number",begin:t.C_NUMBER_RE+"\\b",relevance:0},p,g,s,o],b=[...m];return b.pop(),b.push(l),d.contains=b,{name:"YAML",case_insensitive:!0,aliases:["yml"],contains:m}}function ac(t){let e=t.regex,i={},n={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[i]}]};Object.assign(i,{className:"variable",variants:[{begin:e.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},n]});let r={className:"subst",begin:/\$\(/,end:/\)/,contains:[t.BACKSLASH_ESCAPE]},s=t.inherit(t.COMMENT(),{match:[/(^|\s)/,/#.*$/],scope:{2:"comment"}}),o={begin:/<<-?\s*(?=\w+)/,starts:{contains:[t.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},l={className:"string",begin:/"/,end:/"/,contains:[t.BACKSLASH_ESCAPE,i,r]};r.contains.push(l);let a={match:/\\"/},h={className:"string",begin:/'/,end:/'/},c={match:/\\'/},f={begin:/\$?\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},t.NUMBER_MODE,i]},u=["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"],d=t.SHEBANG({binary:`(${u.join("|")})`,relevance:10}),p={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[t.inherit(t.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},g=["if","then","else","elif","fi","time","for","while","until","in","do","done","case","esac","coproc","function","select"],m=["true","false"],b={match:/(\/[a-z._-]+)+/},y=["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset"],x=["alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","sudo","type","typeset","ulimit","unalias"],Q=["autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp"],S=["chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir"," Line truncated
display: block;
overflow-x: auto;
padding: 1em
}
code.hljs {
padding: 3px 5px
}
/*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/
.hljs {
color: #24292e;
background: #ffffff
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
/* prettylights-syntax-keyword */
color: #d73a49
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
/* prettylights-syntax-entity */
color: #6f42c1
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-variable,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
/* prettylights-syntax-constant */
color: #005cc5
}
.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
/* prettylights-syntax-string */
color: #032f62
}
.hljs-built_in,
.hljs-symbol {
/* prettylights-syntax-variable */
color: #e36209
}
.hljs-comment,
.hljs-code,
.hljs-formula {
/* prettylights-syntax-comment */
color: #6a737d
}
.hljs-name,
.hljs-quote,
.hljs-selector-tag,
.hljs-selector-pseudo {
/* prettylights-syntax-entity-tag */
color: #22863a
}
.hljs-subst {
/* prettylights-syntax-storage-modifier-import */
color: #24292e
}
.hljs-section {
/* prettylights-syntax-markup-heading */
color: #005cc5;
font-weight: bold
}
.hljs-bullet {
/* prettylights-syntax-markup-list */
color: #735c0f
}
.hljs-emphasis {
/* prettylights-syntax-markup-italic */
color: #24292e;
font-style: italic
}
.hljs-strong {
/* prettylights-syntax-markup-bold */
color: #24292e;
font-weight: bold
}
.hljs-addition {
/* prettylights-syntax-markup-inserted */
color: #22863a;
background-color: #f0fff4
}
.hljs-deletion {
/* prettylights-syntax-markup-deleted */
color: #b31d28;
background-color: #ffeef0
}
.hljs-char.escape_,
.hljs-link,
.hljs-params,
.hljs-property,
.hljs-punctuation,
.hljs-tag {
/* purposely ignored */
}`;var hg=`pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em
}
code.hljs {
padding: 3px 5px
}
/*!
Theme: GitHub Dark Dimmed
Description: Dark dimmed theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Colors taken from GitHub's CSS
*/
.hljs {
color: #adbac7;
background: #22272e
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
/* prettylights-syntax-keyword */
color: #f47067
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
/* prettylights-syntax-entity */
color: #dcbdfb
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-variable,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
/* prettylights-syntax-constant */
color: #6cb6ff
}
.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
/* prettylights-syntax-string */
color: #96d0ff
}
.hljs-built_in,
.hljs-symbol {
/* prettylights-syntax-variable */
color: #f69d50
}
.hljs-comment,
.hljs-code,
.hljs-formula {
/* prettylights-syntax-comment */
color: #768390
}
.hljs-name,
.hljs-quote,
.hljs-selector-tag,
.hljs-selector-pseudo {
/* prettylights-syntax-entity-tag */
color: #8ddb8c
}
.hljs-subst {
/* prettylights-syntax-storage-modifier-import */
color: #adbac7
}
.hljs-section {
/* prettylights-syntax-markup-heading */
color: #316dca;
font-weight: bold
}
.hljs-bullet {
/* prettylights-syntax-markup-list */
color: #eac55f
}
.hljs-emphasis {
/* prettylights-syntax-markup-italic */
color: #adbac7;
font-style: italic
}
.hljs-strong {
/* prettylights-syntax-markup-bold */
color: #adbac7;
font-weight: bold
}
.hljs-addition {
/* prettylights-syntax-markup-inserted */
color: #b4f1b4;
background-color: #1b4721
}
.hljs-deletion {
/* prettylights-syntax-markup-deleted */
color: #ffd8d3;
background-color: #78191b
}
.hljs-char.escape_,
.hljs-link,
.hljs-params,
.hljs-property,
.hljs-punctuation,
.hljs-tag {
/* purposely ignored */
}`;var Ce={timestamp:Pe.define(),bracket:Pe.define(),category:Pe.define(),logString:Pe.define(),logLink:Pe.define(),levelInfo:Pe.define(),levelWarning:Pe.define(),levelError:Pe.define(),levelDebug:Pe.define(),levelTip:Pe.define(),levelFatal:Pe.define(),levelWatchdog:Pe.define()};Ei.registerLanguage("yaml",ag);Ei.registerLanguage("yml",ag);Ei.registerLanguage("bash",ac);Ei.registerLanguage("sh",ac);Ei.registerLanguage("shell",ac);Ei.registerLanguage("json",wk);var hX=[{label:"port",type:"keyword",detail:"HTTP proxy port",info:"Invalid when mixed port is enabled"},{label:"socks-port",type:"keyword",detail:"SOCKS5 proxy port"},{label:"mixed-port",type:"keyword",detail:"HTTP/SOCKS mixed port",info:"Overrides port and socks-port when set"},{label:"redir-port",type:"keyword",detail:"Transparent proxy port"},{label:"tproxy-port",type:"keyword",detail:"TPROXY transparent proxy port"},{label:"mode",type:"keyword",detail:"Run mode: rule / global / direct"},{label:"log-level",type:"keyword",detail:"Log level: debug / info / warning / error / silent"},{label:"ipv6",type:"keyword",detail:"IPv6 traffic handling: true / false"},{label:"allow-lan",type:"keyword",detail:"Allow LAN connections: true / false"},{label:"bind-address",type:"keyword",detail:"Bind address, default *"},{label:"authentication",type:"keyword",detail:"HTTP/SOCKS authentication, array format"},{label:"external-controller",type:"keyword",detail:"RESTful API listen address"},{label:"external-ui",type:"keyword",detail:"Dashboard path"},{label:"secret",type:"keyword",detail:"API secret"},{label:"interface-name",type:"keyword",detail:"Outbound interface name"},{label:"routing-mark",type:"keyword",detail:"Routing mark"},{label:"hosts",type:"keyword",detail:"Custom hosts mapping"},{label:"profile",type:"keyword",detail:"Profiling configuration"},{label:"global-ua",type:"keyword",detail:"Global User-Agent"},{label:"unified-delay",type:"keyword",detail:"Unified delay: true / false"},{label:"tcp-concurrent",type:"keyword",detail:"TCP concurrent connections"},{label:"find-process-mode",type:"keyword",detail:"Find process mode: off / strict / always"},{label:"sniffing",type:"keyword",detail:"Domain sniffing: true / false"},{label:"keep-alive-interval",type:"keyword",detail:"TCP keep-alive interval (seconds)"},{label:"geodata-mode",type:"keyword",detail:"GEO data mode: true / false"},{label:"geodata-loader",type:"keyword",detail:"GEO loader: memconservative / standard"},{label:"geox-url",type:"keyword",detail:"GEOX custom URL template"},{label:"geosite",type:"keyword",detail:"GeoSite configuration"},{label:"geo-auto-update",type:"keyword",detail:"GEO auto update: true / false"},{label:"geo-update-interval",type:"keyword",detail:"GEO update interval (hours)"},{label:"tun",type:"keyword",detail:"TUN mode configuration"},{label:"enable",type:"property",detail:"Enable: true / false"},{label:"stack",type:"property",detail:"Protocol stack: system / gvisor / mixed"},{label:"device",type:"property",detail:"TUN device name"},{label:"dns-hijack",type:"property",detail:"DNS hijack address list"},{label:"auto-route",type:"property",detail:"Auto set route: true / false"},{label:"auto-detect-interface",type:"property",detail:"Auto detect interface: true / false"},{label:"mtu",type:"property",detail:"MTU value"},{label:"inet4-address",type:"property",detail:"IPv4 address range"},{label:"inet6-address",type:"property",detail:"IPv6 address range"},{label:"strict-route",type:"property",detail:"Strict route: true / false"},{label:"endpoint-independent-nat",type:"property",detail:"Endpoint-independent NAT: true / false"},{label:"udp-timeout",type:"property",detail:"UDP timeout"},{label:"dns",type:"keyword",detail:"DNS configuration"},{label:"nameserver",type:"property",detail:"DNS upstream servers"},{label:"fallback",type:"property",detail:"Fallback DNS servers"},{label:"fallback-filter",type:"property",detail:"Fallback filter configuration"},{label:"default-nameserver",type:"property",detail:"Default DNS servers"},{label:"nameserver-policy",type:"property",detail:"DNS by domain name"},{label:"proxy-server-nameserver",type:"property",detail:"Proxy DNS servers"},{label:"use-hosts",type:"property",detail:"Use hosts: true / false"},{label:"enhanced-mode",type:"property",detail:"DNS mode: normal / redir-host / fake-ip"},{label:"fake-ip-range",type:"property",detail:"Fake-IP address range"},{label:"fake-ip-filter",type:"property",detail:"Fake-IP filter domains"},{label:"type",type:"type",detail:"ss / ssr / vmess / trojan / snell / http / socks5 / hysteria / vless / tuic / wireguard"},{label:"server",type:"property",detail:"Server address"},{label:"name",type:"property",detail:"Proxy name"},{label:"password",type:"property",detail:"Password"},{label:"cipher",type:"property",detail:"Encryption method"},{label:"udp",type:"property",detail:"UDP relay: true / false"},{label:"xudp",type:"property",detail:"XUDP mode"},{label:"tfo",type:"property",detail:"TCP Fast Open: true / false"},{label:"mpt Line truncated
mode: #{2}
log-level: #{3}
allow-lan: #{4}
bind-address: "#{5}"
ipv6: #{6}
external-controller: 0.0.0.0:9093
#{}`,{label:"config-base",type:"snippet",detail:"Basic configuration"}),A(`- name: "#{1}"
type: ss
server: "#{2}"
port: #{3}
cipher: #{4}
password: "#{5}"
# udp: true
# plugin: obfs
# plugin-opts:
# mode: tls
# host: bing.com
# client-fingerprint: chrome
# smux:
# enabled: false
#{}`,{label:"ss-template",type:"snippet",detail:"Shadowsocks node"}),A(`- name: "#{1}"
type: ssr
server: "#{2}"
port: #{3}
cipher: #{4}
password: "#{5}"
obfs: #{6}
protocol: #{7}
# obfs-param: ""
# protocol-param: ""
# udp: true
#{}`,{label:"ssr-template",type:"snippet",detail:"ShadowsocksR node"}),A(`- name: "#{1}"
type: vmess
server: "#{2}"
port: #{3}
uuid: "#{4}"
alterId: #{5}
cipher: auto
# udp: true
# network: ws
# tls: true
# servername: ""
# skip-cert-verify: false
# client-fingerprint: chrome
# ws-opts:
# path: /
# headers:
# Host: ""
#{}`,{label:"vmess-template",type:"snippet",detail:"VMess node"}),A(`- name: "#{1}"
type: vmess
server: "#{2}"
port: #{3}
uuid: "#{4}"
alterId: 0
cipher: auto
network: grpc
tls: true
servername: "#{5}"
# skip-cert-verify: false
# client-fingerprint: chrome
grpc-opts:
grpc-service-name: "#{6}"
#{}`,{label:"vmess-grpc",type:"snippet",detail:"VMess gRPC node"}),A(`- name: "#{1}"
type: trojan
server: "#{2}"
port: #{3}
password: "#{4}"
# udp: true
# sni: ""
# skip-cert-verify: false
# client-fingerprint: chrome
# network: ws
# ws-opts:
# path: /
#{}`,{label:"trojan-template",type:"snippet",detail:"Trojan node"}),A(`- name: "#{1}"
type: vless
server: "#{2}"
port: #{3}
uuid: "#{4}"
# udp: true
# network: tcp
# tls: true
# servername: ""
# flow: xtls-rprx-vision
# client-fingerprint: chrome
# reality-opts:
# public-key: ""
# short-id: ""
#{}`,{label:"vless-template",type:"snippet",detail:"VLESS node"}),A(`- name: "#{1}"
type: vless
server: "#{2}"
port: #{3}
uuid: "#{4}"
network: tcp
tls: true
udp: true
flow: xtls-rprx-vision
client-fingerprint: chrome
servername: "#{5}"
reality-opts:
public-key: "#{6}"
short-id: "#{7}"
#{}`,{label:"vless-reality",type:"snippet",detail:"VLESS REALITY node"}),A(`- name: "#{1}"
type: hysteria2
server: "#{2}"
port: #{3}
password: "#{4}"
# up: "30 Mbps"
# down: "200 Mbps"
# sni: ""
# skip-cert-verify: false
# obfs: salamander
# obfs-password: ""
#{}`,{label:"hysteria2-template",type:"snippet",detail:"Hysteria2 node"}),A(`- name: "#{1}"
type: tuic
server: "#{2}"
port: #{3}
uuid: "#{4}"
password: "#{5}"
# udp-relay-mode: native
# sni: ""
# skip-cert-verify: false
# alpn:
# - h3
# congestion-controller: bbr
#{}`,{label:"tuic-template",type:"snippet",detail:"TUIC node"}),A(`- name: "#{1}"
type: wireguard
server: "#{2}"
port: #{3}
ip: "#{4}"
# ipv6: ""
public-key: "#{5}"
private-key: "#{6}"
udp: true
# reserved: ""
# dialer-proxy: ""
#{}`,{label:"wireguard-template",type:"snippet",detail:"WireGuard node"}),A(`- name: "#{1}"
type: socks5
server: "#{2}"
port: #{3}
# username: ""
# password: ""
# tls: true
# skip-cert-verify: true
# udp: true
#{}`,{label:"socks5-template",type:"snippet",detail:"SOCKS5 node"}),A(`- name: "#{1}"
type: http
server: "#{2}"
port: #{3}
# username: ""
# password: ""
# tls: true
# skip-cert-verify: true
#{}`,{label:"http-template",type:"snippet",detail:"HTTP node"}),A(`- name: "#{1}"
type: snell
server: "#{2}"
port: #{3}
psk: "#{4}"
version: #{5}
# udp: true
# obfs-opts:
# mode: http
# host: bing.com
#{}`,{label:"snell-template",type:"snippet",detail:"Snell node"}),A(`- name: "#{1}"
type: hysteria
server: "#{2}"
port: #{3}
auth-str: "#{4}"
protocol: udp
up: "#{5}"
down: "#{6}"
# sni: ""
# skip-cert-verify: false
# alpn:
# - h3
#{}`,{label:"hysteria-template",type:"snippet",detail:"Hysteria (v1) node"}),A(`- name: "#{1}"
type: mieru
server: "#{2}"
port: #{3}
transport: TCP
username: "#{4}"
password: "#{5}"
udp: true
# multiplexing: MULTIPLEXING_LOW
# handshake-mode: HANDSHAKE_STANDARD
#{}`,{label:"mieru-template",type:"snippet",detail:"Mieru node"}),A(`- name: "#{1}"
type: anytls
server: "#{2}"
port: #{3}
password: "#{4}"
# udp: true
# sni: ""
# skip-cert-verify: true
# client-fingerprint: chrome
# alpn:
# - h2
#{}`,{label:"anytls-template",type:"snippet",detail:"AnyTLS node"}),A(`- name: "#{1}"
type: trusttunnel
server: "#{2}"
port: #{3}
username: "#{4}"
password: "#{5}"
udp: true
# sni: ""
# skip-cert-verify: true
# client-fingerprint: chrome
# quic: true
# congestion-controller: bbr
#{}`,{label:"trusttunnel-template",type:"snippet",detail:"TrustTunnel node"}),A(`- name: "#{1}"
type: sudoku
server: "#{2}"
port: #{3}
key: "#{4}"
aead-method: #{5}
# padding-min: 2
# padding-max: 7
# table-type: prefer_ascii
# httpmask:
# disable: false
# mode: legacy
#{}`,{label:"sudoku-template",type:"snippet",detail:"Sudoku node"}),A(`- name: "#{1}"
type: openvpn
server: "#{2}"
port: #{3}
proto: udp
# username: ""
# password: ""
ca: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
cert: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
udp: true
#{}`,{label:"openvpn-template",type:"snippet",detail:"OpenVPN node"}),A(`- name: "#{1}"
type: ssh
server: "#{2}"
port: #{3}
username: "#{4}"
# password: ""
# privateKey: path
#{}`,{label:"ssh-template",type:"snippet",detail:"SSH node"}),A(`- name: "#{1}"
type: dns
#{}`,{label:"dns-out-template",type:"snippet",detail:"DNS outbound"}),A(`- name: "#{1}"
type: direct
# interface-name: en0
# routing-mark: 6667
#{}`,{label:"direct-template",type:"snippet",detail:"Direct outbound (custom interface)"}),A(`- name: "#{1}"
type: select
proxies:
- "#{2}"
# disable-udp: false
#{}`,{label:"group-select",type:"snippet",detail:"Select manual proxy group"}),A(`- name: "#{1}"
type: url-test
proxies:
- "#{2}"
url: "#{3}"
interval: #{4}
# tolerance: 150
# lazy: true
#{}`,{label:"group-url-test",type:"snippet",detail:"URL-Test auto speed test group"}),A(`- name: "#{1}"
type: fallback
proxies:
- "#{2}"
url: "#{3}"
interval: #{4}
#{}`,{label:"group-fallback",type:"snippet",detail:"Fallback failover group"}),A(`- name: "#{1}"
type: load-balance
proxies:
- "#{2}"
url: "#{3}"
interval: #{4}
# strategy: consistent-hashing
#{}`,{label:"group-load-balance",type:"snippet",detail:"Load-Balance group"}),A(`- name: "#{1}"
type: smart
proxies:
- "#{2}"
url: "#{3}"
interval: #{4}
# timeout: 5000
# max-failed-times: 3
# lazy: true
# disable-udp: false
# filter: "HK|SG"
# policy-priority: ""
# uselightgbm: false
# collectdata: false
# sample-rate: 1.0
# prefer-asn: false
#{}`,{label:"group-smart",type:"snippet",detail:"Smart selection group"}),A(`- DOMAIN-SUFFIX,#{1},#{2}
#{}`,{label:"rule-domain-suffix",type:"snippet",detail:"Domain suffix rule"}),A(`- DOMAIN,#{1},#{2}
#{}`,{label:"rule-domain",type:"snippet",detail:"Domain rule"}),A(`- DOMAIN-KEYWORD,#{1},#{2}
#{}`,{label:"rule-domain-keyword",type:"snippet",detail:"Domain keyword rule"}),A(`- GEOSITE,#{1},#{2}
#{}`,{label:"rule-geosite",type:"snippet",detail:"GeoSite rule"}),A(`- GEOIP,#{1},#{2}
#{}`,{label:"rule-geoip",type:"snippet",detail:"GEOIP rule"}),A(`- IP-CIDR,#{1},#{2}
#{}`,{label:"rule-ip-cidr",type:"snippet",detail:"IP-CIDR rule"}),A(`- RULE-SET,#{1},#{2}
#{}`,{label:"rule-set",type:"snippet",detail:"RULE-SET rule"}),A(`- MATCH,#{1}
#{}`,{label:"rule-match",type:"snippet",detail:"MATCH fallback rule"}),A(`dns:
enable: #{1}
listen: 0.0.0.0:53
enhanced-mode: #{2}
default-nameserver:
- 114.114.114.114
- 8.8.8.8
nameserver:
- "#{3}"
# fallback:
# - ""
# fallback-filter:
# geoip: true
# geoip-code: CN
#{}`,{label:"dns-template",type:"snippet",detail:"DNS configuration"}),A(`nameserver-policy:
"#{1}":
- "#{2}"
#{}`,{label:"dns-nameserver-policy",type:"snippet",detail:"DNS nameserver-policy"}),A(`tun:
enable: #{1}
stack: #{2}
device: utun
auto-route: #{3}
auto-detect-interface: #{4}
dns-hijack:
- any:53
# auto-redirect: false
# mtu: 9000
#{}`,{label:"tun-template",type:"snippet",detail:"TUN configuration"}),A(`proxy-providers:
#{1}:
type: http
url: "#{2}"
interval: #{3}
path: ./proxy_provider/#{1}.yaml
# proxy: DIRECT
# header:
# User-Agent:
# - "mihomo/1.0"
health-check:
enable: #{4}
url: https://cp.cloudflare.com/generate_204
interval: #{5}
# override:
# skip-cert-verify: true
# udp: true
# filter: "HK|TW|SG"
# exclude-filter: "Expired|Traffic"
#{}`,{label:"proxy-providers",type:"snippet",detail:"Proxy provider configuration"}),A(`rule-providers:
#{1}:
type: http
behavior: #{2}
url: "#{3}"
interval: #{4}
path: ./rule_provider/#{1}.#{5}
format: #{6}
#{}`,{label:"rule-providers",type:"snippet",detail:"Rule provider configuration"}),A(`rule-providers:
#{1}:
type: file
behavior: #{2}
path: /path/to/#{1}.yaml
format: #{3}
#{}`,{label:"rule-providers-file",type:"snippet",detail:"Rule provider (local file)"}),A(`rule-providers:
#{1}:
type: inline
behavior: #{2}
payload:
- '#{3}'
#{}`,{label:"rule-providers-inline",type:"snippet",detail:"Rule provider (inline)"}),A(`hosts:
'#{1}': #{2}
# '*.: 127.0.0.1
# 'alpha..': '::1'
# 'baidu.com': google.com
#{}`,{label:"hosts",type:"snippet",detail:"Custom hosts mapping"}),A(`fake-ip-filter:
- '#{1}'
- '+.#{2}'
# - rule-set:fakeip-filter
# - geosite:fakeip-filter
# - '*.lan'
# - localhost.ptlogin2.qq.com
#{}`,{label:"fake-ip-filter",type:"snippet",detail:"Fake-IP filter list"}),A(`sniffer:
enable: #{1}
override-destination: #{2}
sniff:
TLS:
ports: [443]
HTTP:
ports: [80, 8080-8880]
override-destination: true
QUIC:
ports: [443]
# force-domain:
# - +.v2ex.com
# skip-domain:
# - Mijia Cloud
# parse-pure-ip: true
# force-dns-mapping: true
#{}`,{label:"sniffer",type:"snippet",detail:"Domain sniffing configuration"}),A(`dns:
enable: #{1}
enhanced-mode: #{2}
listen: 0.0.0.0:53
ipv6: #{3}
default-nameserver:
- 114.114.114.114
- 8.8.8.8
nameserver:
- 114.114.114.114
- tls://223.5.5.5:853
- https://doh.pub/dns-query
# fallback:
# - tls://1.1.1.1
# fallback-filter:
# geoip: true
# geoip-code: CN
# proxy-server-nameserver:
# - https://doh.pub/dns-query
# respect-rules: false
#{}`,{label:"dns",type:"snippet",detail:"DNS configuration"}),A(`nameserver-policy:
"#{1}":
- "#{2}"
# "geosite:cn,private,apple":
# - https://doh.pub/dns-query
# - https://dns.alidns.com/dns-query
# "geosite:category-ads-all": rcode://success
# "rule-set:global,dns": 8.8.8.8
#{}`,{label:"nameserver-policy",type:"snippet",detail:"DNS by domain/geo/rule-set"}),A(`fallback-filter:
geoip: #{1}
geoip-code: #{2}
ipcidr:
- 240.0.0.0/4
- 0.0.0.0/32
# domain:
# - '+.google.com'
# - '+.facebook.com'
#{}`,{label:"fallback-filter",type:"snippet",detail:"DNS fallback filter criteria"}),A(`tun:
enable: #{1}
stack: #{2}
device: utun
auto-route: #{3}
auto-detect-interface: #{4}
dns-hijack:
- any:53
# auto-redirect: false
# mtu: 9000
# strict-route: true
# endpoint-independent-nat: false
#{}`,{label:"tun",type:"snippet",detail:"TUN mode configuration"}),A(`authentication:
- "#{1}:#{2}"
#{}`,{label:"authentication",type:"snippet",detail:"HTTP/SOCKS authentication"}),A(`geox-url:
geoip: "#{1}"
geosite: "#{2}"
mmdb: "#{3}"
#{}`,{label:"geox-url",type:"snippet",detail:"Custom GEO data source URL"}),A(`profile:
store-selected: #{1}
store-fake-ip: #{2}
#{}`,{label:"profile",type:"snippet",detail:"Persistent storage configuration"}),A(`- name: "#{1}"
type: select
use:
- #{2}
# filter: "HK|SG"
# exclude-filter: "Expired|Traffic"
proxies:
- DIRECT
#{}`,{label:"proxy-group-use",type:"snippet",detail:"Proxy group (reference provider)"}),A(`listeners:
- name: socks5-in
type: socks
port: #{1}
# listen: 0.0.0.0
# udp: true
#{}`,{label:"listener-socks",type:"snippet",detail:"SOCKS5 inbound"}),A(`listeners:
- name: http-in
type: http
port: #{1}
# listen: 0.0.0.0
#{}`,{label:"listener-http",type:"snippet",detail:"HTTP inbound"}),A(`listeners:
- name: mixed-in
type: mixed
port: #{1}
# listen: 0.0.0.0
# udp: true
# users:
# - username: aaa
# password: aaa
#{}`,{label:"listener-mixed",type:"snippet",detail:"HTTP/SOCKS mixed inbound"}),A(`listeners:
- name: tun-in
type: tun
# stack: system
# dns-hijack:
# - 0.0.0.0:53
# auto-route: true
# mtu: 9000
#{}`,{label:"listener-tun",type:"snippet",detail:"TUN inbound"}),A(`sub-rules:
#{1}:
- DOMAIN,#{2},#{3}
- DOMAIN-SUFFIX,#{4},#{5}
- IP-CIDR,#{6},#{7}
- MATCH,#{8}
#{}`,{label:"sub-rules",type:"snippet",detail:"Sub-rule set definition"}),A(`tunnels:
- tcp/udp,127.0.0.1:#{1},#{2}:#{3},#{4}
#{}`,{label:"tunnels",type:"snippet",detail:"Tunnel forwarding (short format)"}),A(`tunnels:
- network: [tcp, udp]
address: 127.0.0.1:#{1}
target: #{2}:#{3}
proxy: #{4}
#{}`,{label:"tunnels-full",type:"snippet",detail:"Tunnel forwarding (full format)"}),A(`- name: "#{1}"
type: masque
server: "#{2}"
port: #{3}
public-key: "#{4}"
private-key: "#{5}"
ip: "#{6}"
udp: true
# network: h3 # h3 / h2 / h3-l4proxy
# dialer-proxy: ""
#{}`,{label:"masque-template",type:"snippet",detail:"MASQUE node"}),A(`- name: "#{1}"
type: rematch
target-rematch-name: "#{2}"
# target-sub-rule: ""
#{}`,{label:"rematch-template",type:"snippet",detail:"Rematch node"}),A(`- name: "#{1}"
type: gost-relay
server: "#{2}"
port: #{3}
udp: true
tls: true
# mux: true
# username: ""
# password: ""
#{}`,{label:"gost-relay-template",type:"snippet",detail:"GOST Relay node"})];function uX(t){let e=t.matchBefore(/[\w-]+/);if(!e||e.from===e.to&&!t.explicit)return null;let i=hX.filter(s=>s.label.toLowerCase().startsWith(e.text.toLowerCase())),n=fX.filter(s=>(s.label||s.name||"").toLowerCase().startsWith(e.text.toLowerCase())),r=[...i,...n];return r.length?{from:e.from,options:r,validFor:/^[\w-]*$/}:null}function dX(){return Ad(t=>{let e=[];try{NS(t.state.doc.toString(),{schema:qd})}catch(i){let n=i.mark;if(n&&n.line!==void 0){let r=n.line+1;if(r<=t.state.doc.lines){let s=t.state.doc.line(r),o=Math.min(s.from+(n.column||0),s.to);e.push({from:o,to:Math.min(o+1,s.to),severity:"error",message:i.reason||i.message})}}else e.push({from:0,to:0,severity:"error",message:i.reason||i.message})}return e})}var cc=null,fg=null;function pX(){if(!window.levelTranslations){cc={},fg=/(?!)/;return}var t={},e=[];for(var i in window.levelTranslations)if(window.levelTranslations.hasOwnProperty(i)){var n=window.levelTranslations[i];t[n]=i,e.push(n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"))}cc=t,fg=new RegExp("^\\[("+e.join("|")+")\\]")}var gX=Xs.define({tokenTable:{timestamp:Ce.timestamp,bracket:Ce.bracket,category:Ce.category,logString:Ce.logString,logLink:Ce.logLink,levelInfo:Ce.levelInfo,levelWarning:Ce.levelWarning,levelError:Ce.levelError,levelDebug:Ce.levelDebug,levelTip:Ce.levelTip,levelFatal:Ce.levelFatal,levelWatchdog:Ce.levelWatchdog},startState(){return{tabDone:!1}},token(t,e){if(t.sol()&&(e.tabDone=!1,t.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)))return"timestamp";if(t.eatSpace())return null;var i=t.peek();if(!i)return t.skipToEnd(),null;if(i==="\u3010"&&t.match(/\u3010[^\u3011]*\u3011/))return"bracket";if(e.tabDone)return t.next(),"logString";if(i==="["){cc===null&&pX();var n=t.match(fg);if(n){var r=cc[n[1]];if(r){var s="level"+r.charAt(0).toUpperCase()+r.slice(1);if(Ce[s])return s}return"category"}if(t.match(/\[[A-Z][^\]]*\]/))return"category"}return i!=="["&&(e.tabDone=!0),t.next(),"logString"}}),OX=Wt.define([{tag:Ce.timestamp,class:"cmt-log-timestamp"},{tag:Ce.bracket,class:"cmt-log-bracket"},{tag:Ce.category,class:"cmt-log-category"},{tag:Ce.logString,class:"cmt-log-string"},{tag:Ce.logLink,class:"cmt-log-link"},{tag:Ce.levelInfo,class:"cmt-log-level-info"},{tag:Ce.levelWarning,class:"cmt-log-level-warning"},{tag:Ce.levelError,class:"cmt-log-level-error"},{tag:Ce.levelDebug,class:"cmt-log-level-debug"},{tag:Ce.levelTip,class:"cmt-log-level-tip"},{tag:Ce.levelFatal,class:"cmt-log-level-fatal"},{tag:Ce.levelWatchdog,class:"cmt-log-level-watchdog"}]);function mX(t=[]){return[qh(),Bh(),Wh(),Ih(),Zh(),Dh(),Nh(),jh(),Tf(),$f({placeholderDOM:null}),wf(),Bf(),np(),T.lineWrapping,Qu(),ki.of([...zf,...Nf,...lp,...Pu,...Qf,{key:"Tab",run:function(e){return ku(e)||Il(e)}}]),...t]}var bX=T.baseTheme({".cm-line":{position:"relative"},".cm-oc-im::before":{content:'""',position:"absolute",top:0,left:"6px",right:0,bottom:0,background:"var(--oc-im)",pointerEvents:"none",zIndex:"-1"},"&light":{"--oc-im-c":"#e1e4e8","--oc-im-ca":"#d0d7de"},"&dark":{"--oc-im-c":"#30363d","--oc-im-ca":"#484f58"}});function vk(t,e){let i=0;for(let n=0;n<t.length;n++)if(t[n]===" ")i++;else if(t[n]===" ")i+=e;else break;return i}function yX(t,e,i,n){for(var r=[],s=e;s<=i;s++){var o=vn(t,n.line(s).from,n.line(s).to);o&&r.push({from:o.from,to:o.to})}for(var l=new Int32Array(i-e+1),s=e;s<=i;s++){for(var a=n.line(s).from,h=0,c=0;c<r.length;c++)r[c].from<a&&a<r[c].to&&h++;l[s-e]=h}return l}function SX(t,e,i,n,r){for(var s=r.line(e).from,o=0,l=i;l<=n;l++){var a=vn(t,r.line(l).from,r.line(l).to);a&&a.from<s&&s<a.to&&o++}return o}function xX({highlightActiveBlock:t=!0,hideFirstIndent:e=!1,thickness:i=1,colors:n}={}){var r=n?T.baseTheme({"&light":{"--oc-im-c":n.light||"#e1e4e8","--oc-im-ca":n.activeLight||"#d0d7de"},"&dark":{"--oc-im-c":n.dark||"#30363d","--oc-im-ca":n.activeDark||"#484f58"}}):[];return[bX,r,Se.fromClass(class{constructor(s){this._view=s,this._stepPx=null,this._measurePending=!1,this.decorations=this._build(s),this._scheduleMeasure(s)}update(s){this._view=s.view;var o=s.docChanged||s.viewportChanged||t&&s.selectionSet;o?(this._stepPx=null,this._measurePending=!1,this.decorations=this._build(s.view),this._scheduleMeasure(s.view)):this._measurePending&&(this._measurePending=!1,this.decorations=this._build(s.view))}_scheduleMeasure(s){this._measureId!==void 0&&s.cancelMeasure(this._measureId),this._measureId=s.requestMeasure(this._mkSpec())}_mkSpec(){var s=this;return{read:function(o){for(var l=e?1:0,a=o.state,h=qt(a),c=a.tabSize,f=a.doc,u=f.lineAt(o.viewport.from).number,d=f.lineAt(o.viewport.to).number,p=Math.max(1,u-80),g=Math.min(f.lines,d+80),m=0,b=u;b<=d;b++)if(!(b<p||b>g)){var y=SX(a,b,u,d,f);y>m&&(m=y)}if(m<=l)return-1;for(var x=0,b=u;b<=d;b++)if(!(b<p||b>g)){var Q=f.line(b).text;if(Q.trim()!==""&&vk(Q,c)>=h){var S=o.coordsAtPos(f.line(b).from),k=o.coordsAtPos(f.line(b).from+h);if(S&&k){x=Math.round((k.left-S.left)*100)/100;break}}}return x>0 Line truncated
@@ -1,344 +0,0 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
direction: ltr;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
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;
white-space: nowrap;
}
.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0 !important;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-fat-cursor .CodeMirror-line::selection,
.cm-fat-cursor .CodeMirror-line > span::selection,
.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
.cm-fat-cursor .CodeMirror-line::-moz-selection,
.cm-fat-cursor .CodeMirror-line > span::-moz-selection,
.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
.cm-fat-cursor { caret-color: transparent; }
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: 0;
overflow: hidden;
}
.CodeMirror-ruler {
border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.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-strikethrough {text-decoration: line-through;}
.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, .cm-s-default .cm-type {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-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
.CodeMirror-composing { border-bottom: 2px solid; }
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
.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 {
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 50px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -50px; margin-right: -50px;
padding-bottom: 50px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
z-index: 0;
}
.CodeMirror-sizer {
position: relative;
border-right: 50px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual 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;
outline: 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;
min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
vertical-align: top;
margin-bottom: -50px;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
/* 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;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre.CodeMirror-line,
.CodeMirror-wrap pre.CodeMirror-line-like {
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;
padding: 0.1px; /* Force widget margins to stay inside of the container */
}
.CodeMirror-widget {}
.CodeMirror-rtl pre { direction: rtl; }
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background-color: #ffa;
background-color: rgba(255, 255, 0, .4);
}
/* 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;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }
File diff suppressed because it is too large. Load diff
@@ -1,117 +0,0 @@
// CodeMirror log mode
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Supports log output with level and category highlighting
(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("log", function(config, parserConfig) {
return {
startState: function(basecol) {
return {
basecol: basecol || 0,
tabDone: false
};
},
token: function(stream, state) {
if (stream.sol()) {
state.tabDone = false;
if (stream.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)) {
return "log-timestamp";
}
}
if (stream.eatSpace()) return null;
var ch = stream.peek();
if (!ch) {
stream.skipToEnd();
return null;
}
if (ch === '【') {
if (stream.match(/【[^】]*】/)) {
return "log-bracket";
}
}
if (state.tabDone) {
stream.next();
return "log-string";
}
if (ch === '[' && window.levelTranslations) {
for (var levelKey in window.levelTranslations) {
var levelText = '[' + window.levelTranslations[levelKey] + ']';
if (stream.match(levelText)) {
return "log-level-" + levelKey;
}
}
}
if (ch === '[' && stream.match(/\[[A-Z][^\]]*\]/)) {
return "log-category";
}
if (ch !== '[') {
state.tabDone = true;
}
stream.next();
return "log-string";
}
};
});
CodeMirror.defineMIME("text/x-log", "log");
});
(function() {
function initLogLevelWidth() {
if (!window.levelTranslations) return;
var tempContainer = document.createElement('div');
tempContainer.style.position = 'absolute';
tempContainer.style.visibility = 'hidden';
tempContainer.style.whiteSpace = 'nowrap';
tempContainer.style.fontSize = '15px';
tempContainer.style.fontWeight = '600';
tempContainer.style.fontFamily = 'Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, sans-serif';
tempContainer.style.padding = '0px 5px';
document.body.appendChild(tempContainer);
let maxWidth = 0;
for (var levelKey in window.levelTranslations) {
var translatedText = '[' + window.levelTranslations[levelKey] + ']';
tempContainer.textContent = translatedText;
var width = tempContainer.offsetWidth;
if (width > maxWidth) {
maxWidth = width;
}
}
document.body.removeChild(tempContainer);
if (maxWidth > 0) {
document.documentElement.style.setProperty('--log-level-width', maxWidth + 'px');
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initLogLevelWidth);
} else {
initLogLevelWidth();
}
})();
@@ -1,78 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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("properties", function() {
return {
token: function(stream, state) {
var sol = stream.sol() || state.afterSection;
var eol = stream.eol();
state.afterSection = false;
if (sol) {
if (state.nextMultiline) {
state.inMultiline = true;
state.nextMultiline = false;
} else {
state.position = "def";
}
}
if (eol && ! state.nextMultiline) {
state.inMultiline = false;
state.position = "def";
}
if (sol) {
while(stream.eatSpace()) {}
}
var ch = stream.next();
if (sol && (ch === "#" || ch === "!" || ch === ";")) {
state.position = "comment";
stream.skipToEnd();
return "comment";
} else if (sol && ch === "[") {
state.afterSection = true;
stream.skipTo("]"); stream.eat("]");
return "header";
} else if (ch === "=" || ch === ":") {
state.position = "quote";
return null;
} else if (ch === "\\" && state.position === "quote") {
if (stream.eol()) { // end of line?
// Multiline value
state.nextMultiline = true;
}
}
return state.position;
},
startState: function() {
return {
position : "def", // Current position, "def", "quote" or "comment"
nextMultiline : false, // Is the next line multiline value
inMultiline : false, // Is the current line a multiline value
afterSection : false // Did we just open a section
};
}
};
});
CodeMirror.defineMIME("text/x-properties", "properties");
CodeMirror.defineMIME("text/x-ini", "properties");
});
@@ -1,168 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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, dict) {
for(var i = 0; i < dict.length; i++) {
words[dict[i]] = style;
}
};
var commonAtoms = ["true", "false"];
var commonKeywords = ["if", "then", "do", "else", "elif", "while", "until", "for", "in", "esac", "fi",
"fin", "fil", "done", "exit", "set", "unset", "export", "function"];
var commonCommands = ["ab", "awk", "bash", "beep", "cat", "cc", "cd", "chown", "chmod", "chroot", "clear",
"cp", "curl", "cut", "diff", "echo", "find", "gawk", "gcc", "get", "git", "grep", "hg", "kill", "killall",
"ln", "ls", "make", "mkdir", "openssl", "mv", "nc", "nl", "node", "npm", "ping", "ps", "restart", "rm",
"rmdir", "sed", "service", "sh", "shopt", "shred", "source", "sort", "sleep", "ssh", "start", "stop",
"su", "sudo", "svn", "tee", "telnet", "top", "touch", "vi", "vim", "wall", "wc", "wget", "who", "write",
"yes", "zsh"];
CodeMirror.registerHelper("hintWords", "shell", commonAtoms.concat(commonKeywords, commonCommands));
define('atom', commonAtoms);
define('keyword', commonKeywords);
define('builtin', commonCommands);
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, ch === "`" ? "quote" : "string"));
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 (ch == "<") {
if (stream.match("<<")) return "operator"
var heredoc = stream.match(/^<-?\s*['"]?([^'"]*)['"]?/)
if (heredoc) {
state.tokens.unshift(tokenHeredoc(heredoc[1]))
return 'string-2'
}
}
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, style) {
var close = quote == "(" ? ")" : quote == "{" ? "}" : quote
return function(stream, state) {
var next, escaped = false;
while ((next = stream.next()) != null) {
if (next === close && !escaped) {
state.tokens.shift();
break;
} else if (next === '$' && !escaped && quote !== "'" && stream.peek() != close) {
escaped = true;
stream.backUp(1);
state.tokens.unshift(tokenDollar);
break;
} else if (!escaped && quote !== close && next === quote) {
state.tokens.unshift(tokenString(quote, style))
return tokenize(stream, state)
} else if (!escaped && /['"]/.test(next) && !/['"]/.test(quote)) {
state.tokens.unshift(tokenStringStart(next, "string"));
stream.backUp(1);
break;
}
escaped = !escaped && next === '\\';
}
return style;
};
};
function tokenStringStart(quote, style) {
return function(stream, state) {
state.tokens[0] = tokenString(quote, style)
stream.next()
return tokenize(stream, state)
}
}
var tokenDollar = function(stream, state) {
if (state.tokens.length > 1) stream.eat('$');
var ch = stream.next()
if (/['"({]/.test(ch)) {
state.tokens[0] = tokenString(ch, ch == "(" ? "quote" : ch == "{" ? "def" : "string");
return tokenize(stream, state);
}
if (!/\d/.test(ch)) stream.eatWhile(/\w/);
state.tokens.shift();
return 'def';
};
function tokenHeredoc(delim) {
return function(stream, state) {
if (stream.sol() && stream.string == delim) state.tokens.shift()
stream.skipToEnd()
return "string-2"
}
}
function tokenize(stream, state) {
return (state.tokens[0] || tokenBase) (stream, state);
};
return {
startState: function() {return {tokens:[]};},
token: function(stream, state) {
return tokenize(stream, state);
},
closeBrackets: "()[]{}''\"\"``",
lineComment: '#',
fold: "brace"
};
});
CodeMirror.defineMIME('text/x-sh', 'shell');
// Apache uses a slightly different Media Type for Shell scripts
// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
CodeMirror.defineMIME('application/x-sh', 'shell');
});
@@ -1,120 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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("yaml", function() {
var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i');
return {
token: function(stream, state) {
var ch = stream.peek();
var esc = state.escaped;
state.escaped = false;
/* comments */
if (ch == "#" && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) {
stream.skipToEnd();
return "comment";
}
if (stream.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))
return "string";
if (state.literal && stream.indentation() > state.keyCol) {
stream.skipToEnd(); return "string";
} else if (state.literal) { state.literal = false; }
if (stream.sol()) {
state.keyCol = 0;
state.pair = false;
state.pairStart = false;
/* document start */
if(stream.match('---')) { return "def"; }
/* document end */
if (stream.match('...')) { return "def"; }
/* array list item */
if (stream.match(/\s*-\s+/)) { return 'meta'; }
}
/* inline pairs/lists */
if (stream.match(/^(\{|\}|\[|\])/)) {
if (ch == '{')
state.inlinePairs++;
else if (ch == '}')
state.inlinePairs--;
else if (ch == '[')
state.inlineList++;
else
state.inlineList--;
return 'meta';
}
/* list separator */
if (state.inlineList > 0 && !esc && ch == ',') {
stream.next();
return 'meta';
}
/* pairs separator */
if (state.inlinePairs > 0 && !esc && ch == ',') {
state.keyCol = 0;
state.pair = false;
state.pairStart = false;
stream.next();
return 'meta';
}
/* start of value of a pair */
if (state.pairStart) {
/* block literals */
if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; };
/* references */
if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; }
/* numbers */
if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; }
if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; }
/* keywords */
if (stream.match(keywordRegex)) { return 'keyword'; }
}
/* pairs (associative arrays) -> key */
if (!state.pair && stream.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^\s,\[\]{}#&*!|>'"%@`])[^#:]*(?=:($|\s))/)) {
state.pair = true;
state.keyCol = stream.indentation();
return "atom";
}
if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; }
/* nothing found, continue */
state.pairStart = false;
state.escaped = (ch == '\\');
stream.next();
return null;
},
startState: function() {
return {
pair: false,
pairStart: false,
keyCol: 0,
inlinePairs: 0,
inlineList: 0,
literal: false,
escaped: false
};
},
lineComment: "#",
fold: "indent"
};
});
CodeMirror.defineMIME("text/x-yaml", "yaml");
CodeMirror.defineMIME("text/yaml", "yaml");
});
@@ -1,309 +0,0 @@
/*
Log syntax highlighting styles for CodeMirror
Light mode: .cm-s-log
Dark mode: :root[data-darkmode="true"] .cm-s-log
*/
:root {
--log-level-width: auto;
}
/* ========== Light Mode ========== */
.cm-s-log.CodeMirror {
background-color: #ffffff;
color: #000000;
}
.cm-s-log .CodeMirror-gutters {
background: #f5f5f5;
color: #999;
border-right: 1px solid #ddd;
}
.cm-s-log .CodeMirror-guttermarker,
.cm-s-log .CodeMirror-guttermarker-subtle,
.cm-s-log .CodeMirror-linenumber {
color: #999;
}
.cm-s-log .CodeMirror-cursor {
border-left: 1px solid #000;
}
.cm-s-log.cm-fat-cursor .CodeMirror-cursor {
background-color: #0000ff30 !important;
}
.cm-s-log .cm-animate-fat-cursor {
background-color: #0000ff30 !important;
}
.cm-s-log div.CodeMirror-selected {
background: #e8f2fe;
}
.cm-s-log.CodeMirror-focused div.CodeMirror-selected {
background: #e8f2fe;
}
.cm-s-log .CodeMirror-line::selection,
.cm-s-log .CodeMirror-line>span::selection,
.cm-s-log .CodeMirror-line>span>span::selection {
background: #e8f2fe;
}
.cm-s-log .CodeMirror-line::-moz-selection,
.cm-s-log .CodeMirror-line>span::-moz-selection,
.cm-s-log .CodeMirror-line>span>span::-moz-selection {
background: #e8f2fe;
}
.cm-s-log .CodeMirror-activeline-background {
background: #FFFAE3;
}
.cm-s-log span.cm-meta { color: #808000; }
.cm-s-log span.cm-number { color: #0000FF; }
.cm-s-log span.cm-keyword { line-height: 1em; font-weight: bold; color: #000080; }
.cm-s-log span.cm-atom { font-weight: bold; color: #000080; }
.cm-s-log span.cm-def { color: #000000; }
.cm-s-log span.cm-variable { color: black; }
.cm-s-log span.cm-variable-2 { color: black; }
.cm-s-log span.cm-variable-3,
.cm-s-log span.cm-type { color: black; }
.cm-s-log span.cm-property { color: black; }
.cm-s-log span.cm-operator { color: black; }
.cm-s-log span.cm-comment { color: #808080; }
.cm-s-log span.cm-string { color: #008000; }
.cm-s-log span.cm-qualifier { color: #555; }
.cm-s-log span.cm-error { line-height: 1em; font-weight: bold; color: #FF0000; }
.cm-s-log span.cm-attribute { color: #0000FF; }
.cm-s-log span.cm-tag { color: #000080; }
.cm-s-log span.cm-link { color: #0000FF; }
.cm-s-log span.cm-builtin { color: #30a; }
.cm-s-log span.cm-bracket { color: #cc7; }
.cm-s-log {
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, sans-serif;
}
.cm-s-log .CodeMirror-matchingbracket {
outline: 1px solid grey;
color: black !important;
}
/* Log specific styles - Light Mode */
.cm-s-log span.cm-log-timestamp {
color: #b53cf1;
font-weight: 500;
background-color: rgba(181, 60, 241, 0.15);
padding: 0px 5px;
margin: 2px 0px;
border-radius: 5px;
display: inline-block;
text-align: center;
}
.cm-s-log span.cm-log-level-info,
.cm-s-log span.cm-log-level-warning,
.cm-s-log span.cm-log-level-error,
.cm-s-log span.cm-log-level-debug,
.cm-s-log span.cm-log-level-tip,
.cm-s-log span.cm-log-level-fatal,
.cm-s-log span.cm-log-level-watchdog {
font-weight: 500;
margin: 2px 0px;
border-radius: 5px;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--log-level-width);
}
.cm-s-log span.cm-log-level-info {
color: #25b5b8;
background-color: rgba(37, 181, 184, 0.15);
}
.cm-s-log span.cm-log-level-warning {
color: #ff00bb;
background-color: rgba(255, 0, 187, 0.15);
}
.cm-s-log span.cm-log-level-error {
color: #FF0000;
background-color: rgba(255, 0, 0, 0.15);
}
.cm-s-log span.cm-log-level-debug {
color: #0062ff;
background-color: rgba(0, 98, 255, 0.15);
}
.cm-s-log span.cm-log-level-tip {
color: #FF6B00;
background-color: rgba(255, 107, 0, 0.15);
}
.cm-s-log span.cm-log-level-fatal {
color: #FF0000;
background-color: rgba(255, 0, 0, 0.15);
}
.cm-s-log span.cm-log-level-watchdog {
color: #ffa700;
background-color: rgba(255, 167, 0, 0.15);
}
.cm-s-log span.cm-log-category {
color: #FF6B00;
font-weight: 500;
background-color: rgba(255, 107, 0, 0.15);
padding: 0px 5px;
margin: 2px 0px;
border-radius: 5px;
display: inline-block;
text-align: center;
}
.cm-s-log span.cm-log-bracket { color: #059669; font-weight: 600; }
.cm-s-log span.cm-log-string { color: #000000; font-weight: 400; }
.CodeMirror-hints.log {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
color: #616569;
background-color: #ebf3fd !important;
}
.CodeMirror-hints.log .CodeMirror-hint-active {
background-color: #a2b8c9 !important;
color: #5c6065 !important;
}
/* ========== Dark Mode ========== */
:root[data-darkmode="true"] .cm-s-log.CodeMirror {
background-color: #263238;
color: #EEFFFF;
}
:root[data-darkmode="true"] .cm-s-log .CodeMirror-gutters {
background: #263238;
color: #546E7A;
border: none;
}
:root[data-darkmode="true"] .cm-s-log .CodeMirror-guttermarker,
:root[data-darkmode="true"] .cm-s-log .CodeMirror-guttermarker-subtle,
:root[data-darkmode="true"] .cm-s-log .CodeMirror-linenumber {
color: #546E7A;
}
:root[data-darkmode="true"] .cm-s-log .CodeMirror-cursor {
border-left: 1px solid #FFCC00;
}
:root[data-darkmode="true"] .cm-s-log.cm-fat-cursor .CodeMirror-cursor {
background-color: #5d6d5c80 !important;
}
:root[data-darkmode="true"] .cm-s-log .cm-animate-fat-cursor {
background-color: #5d6d5c80 !important;
}
:root[data-darkmode="true"] .cm-s-log div.CodeMirror-selected {
background: rgba(128, 203, 196, 0.2);
}
:root[data-darkmode="true"] .cm-s-log.CodeMirror-focused div.CodeMirror-selected {
background: rgba(128, 203, 196, 0.2);
}
:root[data-darkmode="true"] .cm-s-log .CodeMirror-line::selection,
:root[data-darkmode="true"] .cm-s-log .CodeMirror-line>span::selection,
:root[data-darkmode="true"] .cm-s-log .CodeMirror-line>span>span::selection {
background: rgba(128, 203, 196, 0.2);
}
:root[data-darkmode="true"] .cm-s-log .CodeMirror-line::-moz-selection,
:root[data-darkmode="true"] .cm-s-log .CodeMirror-line>span::-moz-selection,
:root[data-darkmode="true"] .cm-s-log .CodeMirror-line>span>span::-moz-selection {
background: rgba(128, 203, 196, 0.2);
}
:root[data-darkmode="true"] .cm-s-log .CodeMirror-activeline-background {
background: rgba(0, 0, 0, 0.5);
}
:root[data-darkmode="true"] .cm-s-log span.cm-meta { color: #FFCB6B; }
:root[data-darkmode="true"] .cm-s-log span.cm-number { color: #FF5370; }
:root[data-darkmode="true"] .cm-s-log span.cm-keyword { color: #C792EA; }
:root[data-darkmode="true"] .cm-s-log span.cm-atom { color: #F78C6C; }
:root[data-darkmode="true"] .cm-s-log span.cm-def { color: #82AAFF; }
:root[data-darkmode="true"] .cm-s-log span.cm-variable { color: #f07178; }
:root[data-darkmode="true"] .cm-s-log span.cm-variable-2 { color: #EEFFFF; }
:root[data-darkmode="true"] .cm-s-log span.cm-variable-3,
:root[data-darkmode="true"] .cm-s-log span.cm-type { color: #f07178; }
:root[data-darkmode="true"] .cm-s-log span.cm-property { color: #C792EA; }
:root[data-darkmode="true"] .cm-s-log span.cm-operator { color: #89DDFF; }
:root[data-darkmode="true"] .cm-s-log span.cm-comment { color: #546E7A; }
:root[data-darkmode="true"] .cm-s-log span.cm-string { color: #C3E88D; }
:root[data-darkmode="true"] .cm-s-log span.cm-qualifier { color: #DECB6B; }
:root[data-darkmode="true"] .cm-s-log span.cm-error {
color: rgba(255, 255, 255, 1.0);
background-color: #FF5370;
}
:root[data-darkmode="true"] .cm-s-log span.cm-attribute { color: #C792EA; }
:root[data-darkmode="true"] .cm-s-log span.cm-tag { color: #FF5370; }
:root[data-darkmode="true"] .cm-s-log span.cm-link { color: #82AAFF; }
:root[data-darkmode="true"] .cm-s-log span.cm-builtin { color: #FFCB6B; }
:root[data-darkmode="true"] .cm-s-log span.cm-bracket { color: #F78C6C; }
:root[data-darkmode="true"] .cm-s-log .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}
/* Log specific styles - Dark Mode */
:root[data-darkmode="true"] .cm-s-log span.cm-log-timestamp {
color: #c655ff;
background-color: rgba(198, 85, 255, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-info {
color: #31edf0;
background-color: rgba(49, 237, 240, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-warning {
color: #ff66cc;
background-color: rgba(255, 102, 204, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-error {
color: #FF0000;
background-color: rgba(255, 0, 0, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-debug {
color: #287bff;
background-color: rgba(40, 123, 255, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-tip {
color: #ff6f00;
background-color: rgba(255, 111, 0, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-fatal {
color: #FF0000;
background-color: rgba(255, 0, 0, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-level-watchdog {
color: #ffb833;
background-color: rgba(255, 184, 51, 0.15);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-category {
color: #ff6f00;
background-color: rgba(255, 111, 0, 0.2);
}
:root[data-darkmode="true"] .cm-s-log span.cm-log-bracket { color: #34d399; }
:root[data-darkmode="true"] .cm-s-log span.cm-log-string { color: #ffffff; }
:root[data-darkmode="true"] .CodeMirror-hints.log {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
color: #EEFFFF;
background-color: #37474F !important;
}
:root[data-darkmode="true"] .CodeMirror-hints.log .CodeMirror-hint-active {
background-color: #546E7A !important;
color: #EEFFFF !important;
}
@@ -1,141 +0,0 @@
/*
Name: material
Author: Mattia Astorino (http://github.com/equinusocio)
Website: https://material-theme.site/
*/
.cm-s-material.CodeMirror {
background-color: #263238;
color: #EEFFFF;
}
.cm-s-material .CodeMirror-gutters {
background: #263238;
color: #546E7A;
border: none;
}
.cm-s-material .CodeMirror-guttermarker,
.cm-s-material .CodeMirror-guttermarker-subtle,
.cm-s-material .CodeMirror-linenumber {
color: #546E7A;
}
.cm-s-material .CodeMirror-cursor {
border-left: 1px solid #FFCC00;
}
.cm-s-material.cm-fat-cursor .CodeMirror-cursor {
background-color: #5d6d5c80 !important;
}
.cm-s-material .cm-animate-fat-cursor {
background-color: #5d6d5c80 !important;
}
.cm-s-material div.CodeMirror-selected {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material.CodeMirror-focused div.CodeMirror-selected {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material .CodeMirror-line::selection,
.cm-s-material .CodeMirror-line>span::selection,
.cm-s-material .CodeMirror-line>span>span::selection {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material .CodeMirror-line::-moz-selection,
.cm-s-material .CodeMirror-line>span::-moz-selection,
.cm-s-material .CodeMirror-line>span>span::-moz-selection {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material .CodeMirror-activeline-background {
background: rgba(0, 0, 0, 0.5);
}
.cm-s-material .cm-keyword {
color: #C792EA;
}
.cm-s-material .cm-operator {
color: #89DDFF;
}
.cm-s-material .cm-variable-2 {
color: #EEFFFF;
}
.cm-s-material .cm-variable-3,
.cm-s-material .cm-type {
color: #f07178;
}
.cm-s-material .cm-builtin {
color: #FFCB6B;
}
.cm-s-material .cm-atom {
color: #F78C6C;
}
.cm-s-material .cm-number {
color: #FF5370;
}
.cm-s-material .cm-def {
color: #82AAFF;
}
.cm-s-material .cm-string {
color: #C3E88D;
}
.cm-s-material .cm-string-2 {
color: #f07178;
}
.cm-s-material .cm-comment {
color: #546E7A;
}
.cm-s-material .cm-variable {
color: #f07178;
}
.cm-s-material .cm-tag {
color: #FF5370;
}
.cm-s-material .cm-meta {
color: #FFCB6B;
}
.cm-s-material .cm-attribute {
color: #C792EA;
}
.cm-s-material .cm-property {
color: #C792EA;
}
.cm-s-material .cm-qualifier {
color: #DECB6B;
}
.cm-s-material .cm-variable-3,
.cm-s-material .cm-type {
color: #DECB6B;
}
.cm-s-material .cm-error {
color: rgba(255, 255, 255, 1.0);
background-color: #FF5370;
}
.cm-s-material .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}
@@ -0,0 +1,969 @@
// ============================================================
// CodeMirror 6 Bundle — OpenClash
// Build: npx esbuild tools/codemirror/entry.js --bundle --format=iife --global-name=CM6 --minify --target=es2019 --outfile=root/www/luci-static/resources/openclash/js/cm6.min.js --legal-comments=none --loader:.css=text
// ============================================================
// ---- Core ----
import { EditorView, ViewPlugin, Decoration } from "@codemirror/view"
import { EditorState, Compartment, RangeSetBuilder } from "@codemirror/state"
// ---- View extensions ----
import {
lineNumbers, highlightActiveLine, highlightActiveLineGutter,
highlightSpecialChars, drawSelection, dropCursor,
rectangularSelection, crosshairCursor, keymap as cmKeymap, placeholder
} from "@codemirror/view"
// ---- Commands ----
import {
defaultKeymap, history, historyKeymap, indentWithTab, indentMore,
toggleComment
} from "@codemirror/commands"
// ---- Language core ----
import {
syntaxHighlighting, HighlightStyle, bracketMatching,
foldGutter, indentOnInput, StreamLanguage, foldKeymap, indentUnit,
getIndentUnit, foldable
} from "@codemirror/language"
// ---- Tags ----
import { Tag } from "@lezer/highlight"
// ---- Custom log tags ----
const logTag = {
timestamp: Tag.define(),
bracket: Tag.define(),
category: Tag.define(),
logString: Tag.define(),
logLink: Tag.define(),
levelInfo: Tag.define(),
levelWarning: Tag.define(),
levelError: Tag.define(),
levelDebug: Tag.define(),
levelTip: Tag.define(),
levelFatal: Tag.define(),
levelWatchdog: Tag.define(),
}
// ---- Language packages ----
import { yaml } from "@codemirror/lang-yaml"
import { markdown } from "@codemirror/lang-markdown"
// ---- Legacy modes ----
import { shell } from "@codemirror/legacy-modes/mode/shell"
import { properties } from "@codemirror/legacy-modes/mode/properties"
// ---- Lint ----
import { linter, lintGutter } from "@codemirror/lint"
import { loadAll, YAML11_SCHEMA } from "js-yaml"
// ---- Search ----
import { search, searchKeymap, highlightSelectionMatches } from "@codemirror/search"
// ---- Autocomplete ----
import {
autocompletion, closeBrackets, closeBracketsKeymap, snippetCompletion,
acceptCompletion
} from "@codemirror/autocomplete"
// ---- Theme ----
import { githubDark, githubLight } from "@fsegurai/codemirror-theme-bundle"
// ---- Merge view ----
import { MergeView } from "@codemirror/merge"
// ---- Markdown rendering ----
import { marked } from "marked"
import hljs from "highlight.js/lib/core"
import yamlLang from "highlight.js/lib/languages/yaml"
import bashLang from "highlight.js/lib/languages/bash"
import jsonLang from "highlight.js/lib/languages/json"
import githubLightCSS from "highlight.js/styles/github.css"
import githubDarkCSS from "highlight.js/styles/github-dark-dimmed.css"
hljs.registerLanguage("yaml", yamlLang)
hljs.registerLanguage("yml", yamlLang)
hljs.registerLanguage("bash", bashLang)
hljs.registerLanguage("sh", bashLang)
hljs.registerLanguage("shell", bashLang)
hljs.registerLanguage("json", jsonLang)
// ============================================================
// Mihomo / Clash YAML keyword completion
// ============================================================
const mihomoKeywords = [
{ label: "port", type: "keyword", detail: "HTTP proxy port", info: "Invalid when mixed port is enabled" },
{ label: "socks-port", type: "keyword", detail: "SOCKS5 proxy port" },
{ label: "mixed-port", type: "keyword", detail: "HTTP/SOCKS mixed port", info: "Overrides port and socks-port when set" },
{ label: "redir-port", type: "keyword", detail: "Transparent proxy port" },
{ label: "tproxy-port", type: "keyword", detail: "TPROXY transparent proxy port" },
{ label: "mode", type: "keyword", detail: "Run mode: rule / global / direct" },
{ label: "log-level", type: "keyword", detail: "Log level: debug / info / warning / error / silent" },
{ label: "ipv6", type: "keyword", detail: "IPv6 traffic handling: true / false" },
{ label: "allow-lan", type: "keyword", detail: "Allow LAN connections: true / false" },
{ label: "bind-address", type: "keyword", detail: "Bind address, default *" },
{ label: "authentication", type: "keyword", detail: "HTTP/SOCKS authentication, array format" },
{ label: "external-controller", type: "keyword", detail: "RESTful API listen address" },
{ label: "external-ui", type: "keyword", detail: "Dashboard path" },
{ label: "secret", type: "keyword", detail: "API secret" },
{ label: "interface-name", type: "keyword", detail: "Outbound interface name" },
{ label: "routing-mark", type: "keyword", detail: "Routing mark" },
{ label: "hosts", type: "keyword", detail: "Custom hosts mapping" },
{ label: "profile", type: "keyword", detail: "Profiling configuration" },
{ label: "global-ua", type: "keyword", detail: "Global User-Agent" },
{ label: "unified-delay", type: "keyword", detail: "Unified delay: true / false" },
{ label: "tcp-concurrent", type: "keyword", detail: "TCP concurrent connections" },
{ label: "find-process-mode", type: "keyword", detail: "Find process mode: off / strict / always" },
{ label: "sniffing", type: "keyword", detail: "Domain sniffing: true / false" },
{ label: "keep-alive-interval", type: "keyword", detail: "TCP keep-alive interval (seconds)" },
{ label: "geodata-mode", type: "keyword", detail: "GEO data mode: true / false" },
{ label: "geodata-loader", type: "keyword", detail: "GEO loader: memconservative / standard" },
{ label: "geox-url", type: "keyword", detail: "GEOX custom URL template" },
{ label: "geosite", type: "keyword", detail: "GeoSite configuration" },
{ label: "geo-auto-update", type: "keyword", detail: "GEO auto update: true / false" },
{ label: "geo-update-interval", type: "keyword", detail: "GEO update interval (hours)" },
{ label: "tun", type: "keyword", detail: "TUN mode configuration" },
{ label: "enable", type: "property", detail: "Enable: true / false" },
{ label: "stack", type: "property", detail: "Protocol stack: system / gvisor / mixed" },
{ label: "device", type: "property", detail: "TUN device name" },
{ label: "dns-hijack", type: "property", detail: "DNS hijack address list" },
{ label: "auto-route", type: "property", detail: "Auto set route: true / false" },
{ label: "auto-detect-interface", type: "property", detail: "Auto detect interface: true / false" },
{ label: "mtu", type: "property", detail: "MTU value" },
{ label: "inet4-address", type: "property", detail: "IPv4 address range" },
{ label: "inet6-address", type: "property", detail: "IPv6 address range" },
{ label: "strict-route", type: "property", detail: "Strict route: true / false" },
{ label: "endpoint-independent-nat", type: "property", detail: "Endpoint-independent NAT: true / false" },
{ label: "udp-timeout", type: "property", detail: "UDP timeout" },
{ label: "dns", type: "keyword", detail: "DNS configuration" },
{ label: "nameserver", type: "property", detail: "DNS upstream servers" },
{ label: "fallback", type: "property", detail: "Fallback DNS servers" },
{ label: "fallback-filter", type: "property", detail: "Fallback filter configuration" },
{ label: "default-nameserver", type: "property", detail: "Default DNS servers" },
{ label: "nameserver-policy", type: "property", detail: "DNS by domain name" },
{ label: "proxy-server-nameserver", type: "property", detail: "Proxy DNS servers" },
{ label: "use-hosts", type: "property", detail: "Use hosts: true / false" },
{ label: "enhanced-mode", type: "property", detail: "DNS mode: normal / redir-host / fake-ip" },
{ label: "fake-ip-range", type: "property", detail: "Fake-IP address range" },
{ label: "fake-ip-filter", type: "property", detail: "Fake-IP filter domains" },
{ label: "type", type: "type", detail: "ss / ssr / vmess / trojan / snell / http / socks5 / hysteria / vless / tuic / wireguard" },
{ label: "server", type: "property", detail: "Server address" },
{ label: "name", type: "property", detail: "Proxy name" },
{ label: "password", type: "property", detail: "Password" },
{ label: "cipher", type: "property", detail: "Encryption method" },
{ label: "udp", type: "property", detail: "UDP relay: true / false" },
{ label: "xudp", type: "property", detail: "XUDP mode" },
{ label: "tfo", type: "property", detail: "TCP Fast Open: true / false" },
{ label: "mptcp", type: "property", detail: "Multipath TCP: true / false" },
{ label: "skip-cert-verify", type: "property", detail: "Skip certificate verification: true / false" },
{ label: "sni", type: "property", detail: "TLS SNI" },
{ label: "alpn", type: "property", detail: "TLS ALPN protocol list" },
{ label: "fingerprint", type: "property", detail: "TLS fingerprint" },
{ label: "client-fingerprint", type: "property", detail: "Client fingerprint" },
{ label: "servername", type: "property", detail: "TLS server name" },
{ label: "network", type: "property", detail: "Transport: tcp / ws / grpc / http" },
{ label: "plugin", type: "property", detail: "Plugin: obfs / v2ray-plugin etc." },
{ label: "plugin-opts", type: "property", detail: "Plugin options" },
{ label: "smux", type: "property", detail: "Connection multiplexing config" },
{ label: "proxy-groups", type: "class", detail: "Proxy group list" },
{ label: "proxies", type: "property", detail: "Sub-proxy/sub-group name list" },
{ label: "url", type: "property", detail: "Health check URL" },
{ label: "interval", type: "property", detail: "Check interval (seconds)" },
{ label: "timeout", type: "property", detail: "Check timeout (ms)" },
{ label: "lazy", type: "property", detail: "Lazy loading: true / false" },
{ label: "strategy", type: "property", detail: "Load balance strategy: consistent-hashing / round-robin" },
{ label: "max-failed-times", type: "property", detail: "Max failed times" },
{ label: "tolerance", type: "property", detail: "Latency tolerance (ms)" },
{ label: "disable-udp", type: "property", detail: "Disable UDP: true / false" },
{ label: "hidden", type: "property", detail: "Hidden: true / false" },
{ label: "icon", type: "property", detail: "Icon URL" },
{ label: "filter", type: "property", detail: "Node filter" },
{ label: "exclude-filter", type: "property", detail: "Exclude filter" },
{ label: "exclude-type", type: "property", detail: "Exclude type" },
{ label: "DOMAIN", type: "keyword", info: "Domain name" },
{ label: "DOMAIN-SUFFIX", type: "keyword", info: "Domain suffix" },
{ label: "DOMAIN-KEYWORD", type: "keyword", info: "Domain keyword" },
{ label: "DOMAIN-REGEX", type: "keyword", info: "Domain regex" },
{ label: "GEOSITE", type: "keyword", info: "GeoSite category" },
{ label: "GEOIP", type: "keyword", info: "Country/region code" },
{ label: "IP-CIDR", type: "keyword", info: "IP CIDR range" },
{ label: "IP-CIDR6", type: "keyword", info: "IPv6 CIDR range" },
{ label: "IP-ASN", type: "keyword", info: "ASN number" },
{ label: "SRC-IP-CIDR", type: "keyword", info: "Source IP CIDR" },
{ label: "SRC-PORT", type: "keyword", info: "Source port" },
{ label: "DST-PORT", type: "keyword", info: "Destination port" },
{ label: "PROCESS-NAME", type: "keyword", info: "Process name" },
{ label: "PROCESS-PATH", type: "keyword", info: "Process path" },
{ label: "RULE-SET", type: "keyword", info: "Rule set name" },
{ label: "AND", type: "keyword", info: "Logical AND" },
{ label: "OR", type: "keyword", info: "Logical OR" },
{ label: "NOT", type: "keyword", info: "Logical NOT" },
{ label: "MATCH", type: "keyword", info: "Match all (fallback)" },
{ label: "no-resolve", type: "keyword", info: "Rule modifier: skip DNS resolution" },
{ label: "proxy-providers", type: "class", detail: "Proxy provider configuration" },
{ label: "rule-providers", type: "class", detail: "Rule provider configuration" },
{ label: "behavior", type: "property", detail: "Behavior: classical / ipcidr / domain" },
{ label: "path", type: "property", detail: "Local path" },
{ label: "format", type: "property", detail: "Format: yaml / text / mrs" },
{ label: "health-check", type: "property", detail: "Health check configuration" },
]
// ============================================================
// Mihomo config snippet templates (based on default.yaml)
// ============================================================
const mihomoSnippets = [
// --- Basic configuration ---
snippetCompletion("mixed-port: #{1}\nmode: #{2}\nlog-level: #{3}\nallow-lan: #{4}\nbind-address: \"#{5}\"\nipv6: #{6}\nexternal-controller: 0.0.0.0:9093\n#{}", {
label: "config-base", type: "snippet", detail: "Basic configuration"
}),
// --- Node templates ---
snippetCompletion("- name: \"#{1}\"\n type: ss\n server: \"#{2}\"\n port: #{3}\n cipher: #{4}\n password: \"#{5}\"\n # udp: true\n # plugin: obfs\n # plugin-opts:\n # mode: tls\n # host: bing.com\n # client-fingerprint: chrome\n # smux:\n # enabled: false\n#{}", {
label: "ss-template", type: "snippet", detail: "Shadowsocks node"
}),
snippetCompletion("- name: \"#{1}\"\n type: ssr\n server: \"#{2}\"\n port: #{3}\n cipher: #{4}\n password: \"#{5}\"\n obfs: #{6}\n protocol: #{7}\n # obfs-param: \"\"\n # protocol-param: \"\"\n # udp: true\n#{}", {
label: "ssr-template", type: "snippet", detail: "ShadowsocksR node"
}),
snippetCompletion("- name: \"#{1}\"\n type: vmess\n server: \"#{2}\"\n port: #{3}\n uuid: \"#{4}\"\n alterId: #{5}\n cipher: auto\n # udp: true\n # network: ws\n # tls: true\n # servername: \"\"\n # skip-cert-verify: false\n # client-fingerprint: chrome\n # ws-opts:\n # path: /\n # headers:\n # Host: \"\"\n#{}", {
label: "vmess-template", type: "snippet", detail: "VMess node"
}),
snippetCompletion("- name: \"#{1}\"\n type: vmess\n server: \"#{2}\"\n port: #{3}\n uuid: \"#{4}\"\n alterId: 0\n cipher: auto\n network: grpc\n tls: true\n servername: \"#{5}\"\n # skip-cert-verify: false\n # client-fingerprint: chrome\n grpc-opts:\n grpc-service-name: \"#{6}\"\n#{}", {
label: "vmess-grpc", type: "snippet", detail: "VMess gRPC node"
}),
snippetCompletion("- name: \"#{1}\"\n type: trojan\n server: \"#{2}\"\n port: #{3}\n password: \"#{4}\"\n # udp: true\n # sni: \"\"\n # skip-cert-verify: false\n # client-fingerprint: chrome\n # network: ws\n # ws-opts:\n # path: /\n#{}", {
label: "trojan-template", type: "snippet", detail: "Trojan node"
}),
snippetCompletion("- name: \"#{1}\"\n type: vless\n server: \"#{2}\"\n port: #{3}\n uuid: \"#{4}\"\n # udp: true\n # network: tcp\n # tls: true\n # servername: \"\"\n # flow: xtls-rprx-vision\n # client-fingerprint: chrome\n # reality-opts:\n # public-key: \"\"\n # short-id: \"\"\n#{}", {
label: "vless-template", type: "snippet", detail: "VLESS node"
}),
snippetCompletion("- name: \"#{1}\"\n type: vless\n server: \"#{2}\"\n port: #{3}\n uuid: \"#{4}\"\n network: tcp\n tls: true\n udp: true\n flow: xtls-rprx-vision\n client-fingerprint: chrome\n servername: \"#{5}\"\n reality-opts:\n public-key: \"#{6}\"\n short-id: \"#{7}\"\n#{}", {
label: "vless-reality", type: "snippet", detail: "VLESS REALITY node"
}),
snippetCompletion("- name: \"#{1}\"\n type: hysteria2\n server: \"#{2}\"\n port: #{3}\n password: \"#{4}\"\n # up: \"30 Mbps\"\n # down: \"200 Mbps\"\n # sni: \"\"\n # skip-cert-verify: false\n # obfs: salamander\n # obfs-password: \"\"\n#{}", {
label: "hysteria2-template", type: "snippet", detail: "Hysteria2 node"
}),
snippetCompletion("- name: \"#{1}\"\n type: tuic\n server: \"#{2}\"\n port: #{3}\n uuid: \"#{4}\"\n password: \"#{5}\"\n # udp-relay-mode: native\n # sni: \"\"\n # skip-cert-verify: false\n # alpn:\n # - h3\n # congestion-controller: bbr\n#{}", {
label: "tuic-template", type: "snippet", detail: "TUIC node"
}),
snippetCompletion("- name: \"#{1}\"\n type: wireguard\n server: \"#{2}\"\n port: #{3}\n ip: \"#{4}\"\n # ipv6: \"\"\n public-key: \"#{5}\"\n private-key: \"#{6}\"\n udp: true\n # reserved: \"\"\n # dialer-proxy: \"\"\n#{}", {
label: "wireguard-template", type: "snippet", detail: "WireGuard node"
}),
snippetCompletion("- name: \"#{1}\"\n type: socks5\n server: \"#{2}\"\n port: #{3}\n # username: \"\"\n # password: \"\"\n # tls: true\n # skip-cert-verify: true\n # udp: true\n#{}", {
label: "socks5-template", type: "snippet", detail: "SOCKS5 node"
}),
snippetCompletion("- name: \"#{1}\"\n type: http\n server: \"#{2}\"\n port: #{3}\n # username: \"\"\n # password: \"\"\n # tls: true\n # skip-cert-verify: true\n#{}", {
label: "http-template", type: "snippet", detail: "HTTP node"
}),
snippetCompletion("- name: \"#{1}\"\n type: snell\n server: \"#{2}\"\n port: #{3}\n psk: \"#{4}\"\n version: #{5}\n # udp: true\n # obfs-opts:\n # mode: http\n # host: bing.com\n#{}", {
label: "snell-template", type: "snippet", detail: "Snell node"
}),
snippetCompletion("- name: \"#{1}\"\n type: hysteria\n server: \"#{2}\"\n port: #{3}\n auth-str: \"#{4}\"\n protocol: udp\n up: \"#{5}\"\n down: \"#{6}\"\n # sni: \"\"\n # skip-cert-verify: false\n # alpn:\n # - h3\n#{}", {
label: "hysteria-template", type: "snippet", detail: "Hysteria (v1) node"
}),
snippetCompletion("- name: \"#{1}\"\n type: mieru\n server: \"#{2}\"\n port: #{3}\n transport: TCP\n username: \"#{4}\"\n password: \"#{5}\"\n udp: true\n # multiplexing: MULTIPLEXING_LOW\n # handshake-mode: HANDSHAKE_STANDARD\n#{}", {
label: "mieru-template", type: "snippet", detail: "Mieru node"
}),
snippetCompletion("- name: \"#{1}\"\n type: anytls\n server: \"#{2}\"\n port: #{3}\n password: \"#{4}\"\n # udp: true\n # sni: \"\"\n # skip-cert-verify: true\n # client-fingerprint: chrome\n # alpn:\n # - h2\n#{}", {
label: "anytls-template", type: "snippet", detail: "AnyTLS node"
}),
snippetCompletion("- name: \"#{1}\"\n type: trusttunnel\n server: \"#{2}\"\n port: #{3}\n username: \"#{4}\"\n password: \"#{5}\"\n udp: true\n # sni: \"\"\n # skip-cert-verify: true\n # client-fingerprint: chrome\n # quic: true\n # congestion-controller: bbr\n#{}", {
label: "trusttunnel-template", type: "snippet", detail: "TrustTunnel node"
}),
snippetCompletion("- name: \"#{1}\"\n type: sudoku\n server: \"#{2}\"\n port: #{3}\n key: \"#{4}\"\n aead-method: #{5}\n # padding-min: 2\n # padding-max: 7\n # table-type: prefer_ascii\n # httpmask:\n # disable: false\n # mode: legacy\n#{}", {
label: "sudoku-template", type: "snippet", detail: "Sudoku node"
}),
snippetCompletion("- name: \"#{1}\"\n type: openvpn\n server: \"#{2}\"\n port: #{3}\n proto: udp\n # username: \"\"\n # password: \"\"\n ca: |\n -----BEGIN CERTIFICATE-----\n ...\n -----END CERTIFICATE-----\n cert: |\n -----BEGIN CERTIFICATE-----\n ...\n -----END CERTIFICATE-----\n key: |\n -----BEGIN PRIVATE KEY-----\n ...\n -----END PRIVATE KEY-----\n udp: true\n#{}", {
label: "openvpn-template", type: "snippet", detail: "OpenVPN node"
}),
snippetCompletion("- name: \"#{1}\"\n type: ssh\n server: \"#{2}\"\n port: #{3}\n username: \"#{4}\"\n # password: \"\"\n # privateKey: path\n#{}", {
label: "ssh-template", type: "snippet", detail: "SSH node"
}),
snippetCompletion("- name: \"#{1}\"\n type: dns\n#{}", {
label: "dns-out-template", type: "snippet", detail: "DNS outbound"
}),
snippetCompletion("- name: \"#{1}\"\n type: direct\n # interface-name: en0\n # routing-mark: 6667\n#{}", {
label: "direct-template", type: "snippet", detail: "Direct outbound (custom interface)"
}),
// --- Proxy groups ---
snippetCompletion("- name: \"#{1}\"\n type: select\n proxies:\n - \"#{2}\"\n # disable-udp: false\n#{}", {
label: "group-select", type: "snippet", detail: "Select manual proxy group"
}),
snippetCompletion("- name: \"#{1}\"\n type: url-test\n proxies:\n - \"#{2}\"\n url: \"#{3}\"\n interval: #{4}\n # tolerance: 150\n # lazy: true\n#{}", {
label: "group-url-test", type: "snippet", detail: "URL-Test auto speed test group"
}),
snippetCompletion("- name: \"#{1}\"\n type: fallback\n proxies:\n - \"#{2}\"\n url: \"#{3}\"\n interval: #{4}\n#{}", {
label: "group-fallback", type: "snippet", detail: "Fallback failover group"
}),
snippetCompletion("- name: \"#{1}\"\n type: load-balance\n proxies:\n - \"#{2}\"\n url: \"#{3}\"\n interval: #{4}\n # strategy: consistent-hashing\n#{}", {
label: "group-load-balance", type: "snippet", detail: "Load-Balance group"
}),
snippetCompletion("- name: \"#{1}\"\n type: smart\n proxies:\n - \"#{2}\"\n url: \"#{3}\"\n interval: #{4}\n # timeout: 5000\n # max-failed-times: 3\n # lazy: true\n # disable-udp: false\n # filter: \"HK|SG\"\n # policy-priority: \"\"\n # uselightgbm: false\n # collectdata: false\n # sample-rate: 1.0\n # prefer-asn: false\n#{}", {
label: "group-smart", type: "snippet", detail: "Smart selection group"
}),
// --- Rules ---
snippetCompletion("- DOMAIN-SUFFIX,#{1},#{2}\n#{}", {
label: "rule-domain-suffix", type: "snippet", detail: "Domain suffix rule"
}),
snippetCompletion("- DOMAIN,#{1},#{2}\n#{}", {
label: "rule-domain", type: "snippet", detail: "Domain rule"
}),
snippetCompletion("- DOMAIN-KEYWORD,#{1},#{2}\n#{}", {
label: "rule-domain-keyword", type: "snippet", detail: "Domain keyword rule"
}),
snippetCompletion("- GEOSITE,#{1},#{2}\n#{}", {
label: "rule-geosite", type: "snippet", detail: "GeoSite rule"
}),
snippetCompletion("- GEOIP,#{1},#{2}\n#{}", {
label: "rule-geoip", type: "snippet", detail: "GEOIP rule"
}),
snippetCompletion("- IP-CIDR,#{1},#{2}\n#{}", {
label: "rule-ip-cidr", type: "snippet", detail: "IP-CIDR rule"
}),
snippetCompletion("- RULE-SET,#{1},#{2}\n#{}", {
label: "rule-set", type: "snippet", detail: "RULE-SET rule"
}),
snippetCompletion("- MATCH,#{1}\n#{}", {
label: "rule-match", type: "snippet", detail: "MATCH fallback rule"
}),
// --- DNS ---
snippetCompletion("dns:\n enable: #{1}\n listen: 0.0.0.0:53\n enhanced-mode: #{2}\n default-nameserver:\n - 114.114.114.114\n - 8.8.8.8\n nameserver:\n - \"#{3}\"\n # fallback:\n # - \"\"\n # fallback-filter:\n # geoip: true\n # geoip-code: CN\n#{}", {
label: "dns-template", type: "snippet", detail: "DNS configuration"
}),
snippetCompletion("nameserver-policy:\n \"#{1}\":\n - \"#{2}\"\n#{}", {
label: "dns-nameserver-policy", type: "snippet", detail: "DNS nameserver-policy"
}),
// --- TUN ---
snippetCompletion("tun:\n enable: #{1}\n stack: #{2}\n device: utun\n auto-route: #{3}\n auto-detect-interface: #{4}\n dns-hijack:\n - any:53\n # auto-redirect: false\n # mtu: 9000\n#{}", {
label: "tun-template", type: "snippet", detail: "TUN configuration"
}),
// --- proxy-provider ---
snippetCompletion("proxy-providers:\n #{1}:\n type: http\n url: \"#{2}\"\n interval: #{3}\n path: ./proxy_provider/#{1}.yaml\n # proxy: DIRECT\n # header:\n # User-Agent:\n # - \"mihomo/1.0\"\n health-check:\n enable: #{4}\n url: https://cp.cloudflare.com/generate_204\n interval: #{5}\n # override:\n # skip-cert-verify: true\n # udp: true\n # filter: \"HK|TW|SG\"\n # exclude-filter: \"Expired|Traffic\"\n#{}", {
label: "proxy-providers", type: "snippet", detail: "Proxy provider configuration"
}),
// --- rule-provider ---
snippetCompletion("rule-providers:\n #{1}:\n type: http\n behavior: #{2}\n url: \"#{3}\"\n interval: #{4}\n path: ./rule_provider/#{1}.#{5}\n format: #{6}\n#{}", {
label: "rule-providers", type: "snippet", detail: "Rule provider configuration"
}),
snippetCompletion("rule-providers:\n #{1}:\n type: file\n behavior: #{2}\n path: /path/to/#{1}.yaml\n format: #{3}\n#{}", {
label: "rule-providers-file", type: "snippet", detail: "Rule provider (local file)"
}),
snippetCompletion("rule-providers:\n #{1}:\n type: inline\n behavior: #{2}\n payload:\n - '#{3}'\n#{}", {
label: "rule-providers-inline", type: "snippet", detail: "Rule provider (inline)"
}),
// --- hosts ---
snippetCompletion("hosts:\n '#{1}': #{2}\n # '*.: 127.0.0.1\n # 'alpha..': '::1'\n # 'baidu.com': google.com\n#{}", {
label: "hosts", type: "snippet", detail: "Custom hosts mapping"
}),
// --- fake-ip-filter ---
snippetCompletion("fake-ip-filter:\n - '#{1}'\n - '+.#{2}'\n # - rule-set:fakeip-filter\n # - geosite:fakeip-filter\n # - '*.lan'\n # - localhost.ptlogin2.qq.com\n#{}", {
label: "fake-ip-filter", type: "snippet", detail: "Fake-IP filter list"
}),
// --- sniffer ---
snippetCompletion("sniffer:\n enable: #{1}\n override-destination: #{2}\n sniff:\n TLS:\n ports: [443]\n HTTP:\n ports: [80, 8080-8880]\n override-destination: true\n QUIC:\n ports: [443]\n # force-domain:\n # - +.v2ex.com\n # skip-domain:\n # - Mijia Cloud\n # parse-pure-ip: true\n # force-dns-mapping: true\n#{}", {
label: "sniffer", type: "snippet", detail: "Domain sniffing configuration"
}),
// --- dns (enhanced) ---
snippetCompletion("dns:\n enable: #{1}\n enhanced-mode: #{2}\n listen: 0.0.0.0:53\n ipv6: #{3}\n default-nameserver:\n - 114.114.114.114\n - 8.8.8.8\n nameserver:\n - 114.114.114.114\n - tls://223.5.5.5:853\n - https://doh.pub/dns-query\n # fallback:\n # - tls://1.1.1.1\n # fallback-filter:\n # geoip: true\n # geoip-code: CN\n # proxy-server-nameserver:\n # - https://doh.pub/dns-query\n # respect-rules: false\n#{}", {
label: "dns", type: "snippet", detail: "DNS configuration"
}),
// --- nameserver-policy (enhanced) ---
snippetCompletion("nameserver-policy:\n \"#{1}\":\n - \"#{2}\"\n # \"geosite:cn,private,apple\":\n # - https://doh.pub/dns-query\n # - https://dns.alidns.com/dns-query\n # \"geosite:category-ads-all\": rcode://success\n # \"rule-set:global,dns\": 8.8.8.8\n#{}", {
label: "nameserver-policy", type: "snippet", detail: "DNS by domain/geo/rule-set"
}),
// --- fallback-filter ---
snippetCompletion("fallback-filter:\n geoip: #{1}\n geoip-code: #{2}\n ipcidr:\n - 240.0.0.0/4\n - 0.0.0.0/32\n # domain:\n # - '+.google.com'\n # - '+.facebook.com'\n#{}", {
label: "fallback-filter", type: "snippet", detail: "DNS fallback filter criteria"
}),
// --- TUN ---
snippetCompletion("tun:\n enable: #{1}\n stack: #{2}\n device: utun\n auto-route: #{3}\n auto-detect-interface: #{4}\n dns-hijack:\n - any:53\n # auto-redirect: false\n # mtu: 9000\n # strict-route: true\n # endpoint-independent-nat: false\n#{}", {
label: "tun", type: "snippet", detail: "TUN mode configuration"
}),
// --- authentication ---
snippetCompletion("authentication:\n - \"#{1}:#{2}\"\n#{}", {
label: "authentication", type: "snippet", detail: "HTTP/SOCKS authentication"
}),
// --- geox-url ---
snippetCompletion("geox-url:\n geoip: \"#{1}\"\n geosite: \"#{2}\"\n mmdb: \"#{3}\"\n#{}", {
label: "geox-url", type: "snippet", detail: "Custom GEO data source URL"
}),
// --- profile ---
snippetCompletion("profile:\n store-selected: #{1}\n store-fake-ip: #{2}\n#{}", {
label: "profile", type: "snippet", detail: "Persistent storage configuration"
}),
// --- proxy-groups with use/filter ---
snippetCompletion("- name: \"#{1}\"\n type: select\n use:\n - #{2}\n # filter: \"HK|SG\"\n # exclude-filter: \"Expired|Traffic\"\n proxies:\n - DIRECT\n#{}", {
label: "proxy-group-use", type: "snippet", detail: "Proxy group (reference provider)"
}),
// --- listeners ---
snippetCompletion("listeners:\n - name: socks5-in\n type: socks\n port: #{1}\n # listen: 0.0.0.0\n # udp: true\n#{}", {
label: "listener-socks", type: "snippet", detail: "SOCKS5 inbound"
}),
snippetCompletion("listeners:\n - name: http-in\n type: http\n port: #{1}\n # listen: 0.0.0.0\n#{}", {
label: "listener-http", type: "snippet", detail: "HTTP inbound"
}),
snippetCompletion("listeners:\n - name: mixed-in\n type: mixed\n port: #{1}\n # listen: 0.0.0.0\n # udp: true\n # users:\n # - username: aaa\n # password: aaa\n#{}", {
label: "listener-mixed", type: "snippet", detail: "HTTP/SOCKS mixed inbound"
}),
snippetCompletion("listeners:\n - name: tun-in\n type: tun\n # stack: system\n # dns-hijack:\n # - 0.0.0.0:53\n # auto-route: true\n # mtu: 9000\n#{}", {
label: "listener-tun", type: "snippet", detail: "TUN inbound"
}),
// --- sub-rules ---
snippetCompletion("sub-rules:\n #{1}:\n - DOMAIN,#{2},#{3}\n - DOMAIN-SUFFIX,#{4},#{5}\n - IP-CIDR,#{6},#{7}\n - MATCH,#{8}\n#{}", {
label: "sub-rules", type: "snippet", detail: "Sub-rule set definition"
}),
// --- tunnels ---
snippetCompletion("tunnels:\n - tcp/udp,127.0.0.1:#{1},#{2}:#{3},#{4}\n#{}", {
label: "tunnels", type: "snippet", detail: "Tunnel forwarding (short format)"
}),
snippetCompletion("tunnels:\n - network: [tcp, udp]\n address: 127.0.0.1:#{1}\n target: #{2}:#{3}\n proxy: #{4}\n#{}", {
label: "tunnels-full", type: "snippet", detail: "Tunnel forwarding (full format)"
}),
// --- additional node types ---
snippetCompletion("- name: \"#{1}\"\n type: masque\n server: \"#{2}\"\n port: #{3}\n public-key: \"#{4}\"\n private-key: \"#{5}\"\n ip: \"#{6}\"\n udp: true\n # network: h3 # h3 / h2 / h3-l4proxy\n # dialer-proxy: \"\"\n#{}", {
label: "masque-template", type: "snippet", detail: "MASQUE node"
}),
snippetCompletion("- name: \"#{1}\"\n type: rematch\n target-rematch-name: \"#{2}\"\n # target-sub-rule: \"\"\n#{}", {
label: "rematch-template", type: "snippet", detail: "Rematch node"
}),
snippetCompletion("- name: \"#{1}\"\n type: gost-relay\n server: \"#{2}\"\n port: #{3}\n udp: true\n tls: true\n # mux: true\n # username: \"\"\n # password: \"\"\n#{}", {
label: "gost-relay-template", type: "snippet", detail: "GOST Relay node"
}),
]
function mihomoCompletion(context) {
const word = context.matchBefore(/[\w-]+/)
if (!word || (word.from === word.to && !context.explicit)) return null
const filtered = mihomoKeywords.filter(k =>
k.label.toLowerCase().startsWith(word.text.toLowerCase())
)
const snippets = mihomoSnippets.filter(s => {
const label = (s.label || s.name || '')
return label.toLowerCase().startsWith(word.text.toLowerCase())
})
const options = [...filtered, ...snippets]
if (!options.length) return null
return { from: word.from, options, validFor: /^[\w-]*$/ }
}
function yamlLinter() {
return linter(view => {
const diagnostics = []
try { loadAll(view.state.doc.toString(), { schema: YAML11_SCHEMA }) } catch (e) {
const mark = e.mark
if (mark && mark.line !== undefined) {
const lineNo = mark.line + 1
if (lineNo <= view.state.doc.lines) {
const line = view.state.doc.line(lineNo)
const pos = Math.min(line.from + (mark.column || 0), line.to)
diagnostics.push({ from: pos, to: Math.min(pos + 1, line.to), severity: "error", message: e.reason || e.message })
}
} else {
diagnostics.push({ from: 0, to: 0, severity: "error", message: e.reason || e.message })
}
}
return diagnostics
})
}
var _levelTagMap = null
var _levelRegex = null
function _buildLevelCache() {
if (!window.levelTranslations) { _levelTagMap = {}; _levelRegex = /(?!)/; return }
var map = {}, parts = []
for (var key in window.levelTranslations) {
if (window.levelTranslations.hasOwnProperty(key)) {
var text = window.levelTranslations[key]
map[text] = key
parts.push(text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
}
}
_levelTagMap = map
_levelRegex = new RegExp('^\\[(' + parts.join('|') + ')\\]')
}
const logLanguage = StreamLanguage.define({
tokenTable: {
timestamp: logTag.timestamp,
bracket: logTag.bracket,
category: logTag.category,
logString: logTag.logString,
logLink: logTag.logLink,
levelInfo: logTag.levelInfo,
levelWarning: logTag.levelWarning,
levelError: logTag.levelError,
levelDebug: logTag.levelDebug,
levelTip: logTag.levelTip,
levelFatal: logTag.levelFatal,
levelWatchdog: logTag.levelWatchdog,
},
startState() { return { tabDone: false } },
token(stream, state) {
if (stream.sol()) {
state.tabDone = false
if (stream.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)) return "timestamp"
}
if (stream.eatSpace()) return null
var ch = stream.peek()
if (!ch) { stream.skipToEnd(); return null }
if (ch === '\u3010' && stream.match(/\u3010[^\u3011]*\u3011/)) return "bracket"
if (state.tabDone) { stream.next(); return "logString" }
if (ch === '[') {
if (_levelTagMap === null) _buildLevelCache()
var levelMatch = stream.match(_levelRegex)
if (levelMatch) {
var levelKey = _levelTagMap[levelMatch[1]]
if (levelKey) {
var styleName = 'level' + levelKey.charAt(0).toUpperCase() + levelKey.slice(1)
if (logTag[styleName]) return styleName
}
return "category"
}
if (stream.match(/\[[A-Z][^\]]*\]/)) return "category"
}
if (ch !== '[') { state.tabDone = true }
stream.next()
return "logString"
}
})
const logHighlightStyle = HighlightStyle.define([
{ tag: logTag.timestamp, class: "cmt-log-timestamp" },
{ tag: logTag.bracket, class: "cmt-log-bracket" },
{ tag: logTag.category, class: "cmt-log-category" },
{ tag: logTag.logString, class: "cmt-log-string" },
{ tag: logTag.logLink, class: "cmt-log-link" },
{ tag: logTag.levelInfo, class: "cmt-log-level-info" },
{ tag: logTag.levelWarning, class: "cmt-log-level-warning" },
{ tag: logTag.levelError, class: "cmt-log-level-error" },
{ tag: logTag.levelDebug, class: "cmt-log-level-debug" },
{ tag: logTag.levelTip, class: "cmt-log-level-tip" },
{ tag: logTag.levelFatal, class: "cmt-log-level-fatal" },
{ tag: logTag.levelWatchdog, class: "cmt-log-level-watchdog" },
])
function baseExtensions(extra = []) {
return [
lineNumbers(), highlightActiveLine(), highlightActiveLineGutter(),
highlightSpecialChars(), drawSelection(), dropCursor(),
rectangularSelection(), crosshairCursor(),
bracketMatching(), foldGutter({ placeholderDOM: null }),
indentOnInput(), history(),
highlightSelectionMatches(), EditorView.lineWrapping,
closeBrackets(),
cmKeymap.of([...defaultKeymap, ...historyKeymap, ...searchKeymap, ...closeBracketsKeymap, ...foldKeymap, { key: 'Tab', run: function(v) { return acceptCompletion(v) || indentMore(v) } }]),
...extra
]
}
// ============================================================
// Custom indentation markers
// Replaces @replit/codemirror-indentation-markers (unmaintained).
// Fixes left:2px→6px: @codemirror/view >=~6.29 changed .cm-line
// padding from "0 2px" to "0 2px 0 6px".
// ============================================================
const _ocImBaseTheme = EditorView.baseTheme({
'.cm-line': { position: 'relative' },
'.cm-oc-im::before': {
content: '""',
position: 'absolute',
top: 0,
left: '6px',
right: 0,
bottom: 0,
background: 'var(--oc-im)',
pointerEvents: 'none',
zIndex: '-1',
},
'&light': { '--oc-im-c': '#e1e4e8', '--oc-im-ca': '#d0d7de' },
'&dark': { '--oc-im-c': '#30363d', '--oc-im-ca': '#484f58' },
})
function _ocImIndent(text, ts) {
let n = 0
for (let i = 0; i < text.length; i++) {
if (text[i] === ' ') n++
else if (text[i] === '\t') n += ts
else break
}
return n
}
// Compute per-line structural nesting depth using CM6's foldable() function.
// foldable(state, lineStart, lineEnd) → {from, to} | null
// Returns an array of depths indexed by (lineNo - fl).
function _foldDepth(state, fl, ll, doc) {
var ranges = []
for (var n = fl; n <= ll; n++) {
var fr = foldable(state, doc.line(n).from, doc.line(n).to)
if (fr) ranges.push({ from: fr.from, to: fr.to })
}
var depths = new Int32Array(ll - fl + 1)
for (var n = fl; n <= ll; n++) {
var pos = doc.line(n).from, d = 0
for (var i = 0; i < ranges.length; i++)
if (ranges[i].from < pos && pos < ranges[i].to) d++
depths[n - fl] = d
}
return depths
}
// Single-line version of _foldDepth, for measure.read where the full
// array hasn't been precomputed.
function _foldDepth1(state, lineNo, fl, ll, doc) {
var pos = doc.line(lineNo).from, d = 0
for (var n = fl; n <= ll; n++) {
var fr = foldable(state, doc.line(n).from, doc.line(n).to)
if (fr && fr.from < pos && pos < fr.to) d++
}
return d
}
function indentMarkerExtension({ highlightActiveBlock = true, hideFirstIndent = false, thickness = 1, colors } = {}) {
var extra = colors ? EditorView.baseTheme({
'&light': { '--oc-im-c': colors.light || '#e1e4e8', '--oc-im-ca': colors.activeLight || '#d0d7de' },
'&dark': { '--oc-im-c': colors.dark || '#30363d', '--oc-im-ca': colors.activeDark || '#484f58' },
}) : []
return [
_ocImBaseTheme,
extra,
ViewPlugin.fromClass(class {
constructor(view) {
this._view = view
this._stepPx = null // measured indent-unit pixel width
this._measurePending = false
this.decorations = this._build(view)
this._scheduleMeasure(view)
}
update(u) {
this._view = u.view
var needsRebuild = u.docChanged || u.viewportChanged ||
(highlightActiveBlock && u.selectionSet)
if (needsRebuild) {
this._stepPx = null
this._measurePending = false
this.decorations = this._build(u.view)
this._scheduleMeasure(u.view)
} else if (this._measurePending) {
this._measurePending = false
this.decorations = this._build(u.view)
}
}
_scheduleMeasure(view) {
if (this._measureId !== undefined) view.cancelMeasure(this._measureId)
this._measureId = view.requestMeasure(this._mkSpec())
}
// Measure one indent unit's pixel width in the read phase
// (coordsAtPos is only safe here, not during update).
_mkSpec() {
var self = this
return {
read: function(view) {
var sa = hideFirstIndent ? 1 : 0
var state = view.state, iw = getIndentUnit(state), ts = state.tabSize, doc = state.doc
var fl = doc.lineAt(view.viewport.from).number
var ll = doc.lineAt(view.viewport.to).number
var bl = Math.max(1, fl - 80), el = Math.min(doc.lines, ll + 80)
// Compute max fold depth in visible range
var maxLvl = 0
for (var n = fl; n <= ll; n++) {
if (n < bl || n > el) continue
var fd = _foldDepth1(state, n, fl, ll, doc)
if (fd > maxLvl) maxLvl = fd
}
if (maxLvl <= sa) return -1
// Measure exact pixel width of one indent unit
var stepPx = 0
for (var n = fl; n <= ll; n++) {
if (n < bl || n > el) continue
var t = doc.line(n).text
if (t.trim() === '') continue
if (_ocImIndent(t, ts) >= iw) {
var c0 = view.coordsAtPos(doc.line(n).from)
var c1 = view.coordsAtPos(doc.line(n).from + iw)
if (c0 && c1) { stepPx = Math.round((c1.left - c0.left) * 100) / 100; break }
}
}
return stepPx > 0 ? stepPx : -1
},
write: function(stepPx) {
if (typeof stepPx === 'number') {
self._stepPx = stepPx > 0 ? stepPx : -1
self._measurePending = true
var v = self._view
// Defer dispatch past the current update cycle
queueMicrotask(function() {
if (v && self._measurePending) v.dispatch({})
})
}
}
}
}
_build(view) {
var sa = hideFirstIndent ? 1 : 0
var state = view.state
var iw = getIndentUnit(state)
var ts = state.tabSize
var doc = state.doc
var fl = doc.lineAt(view.viewport.from).number
var ll = doc.lineAt(view.viewport.to).number
var bl = Math.max(1, fl - 80), el = Math.min(doc.lines, ll + 80)
// Compute visual indent levels
var lvls = new Int32Array(el - bl + 1)
var bk = new Uint8Array(el - bl + 1)
for (var n = bl; n <= el; n++) {
var t = doc.line(n).text
var b = t.trim() === ''
bk[n - bl] = b ? 1 : 0
lvls[n - bl] = b ? -1 : Math.floor(_ocImIndent(t, ts) / iw)
}
// Blank lines inherit the shallower of prev/next non-blank level
for (var n = bl; n <= el; n++) {
if (!bk[n - bl]) continue
var p = 0, nx = 0
for (var x = n - 1; x >= bl; x--) if (!bk[x - bl]) { p = lvls[x - bl]; break }
for (var x = n + 1; x <= el; x++) if (!bk[x - bl]) { nx = lvls[x - bl]; break }
lvls[n - bl] = Math.min(p, nx)
}
// Structural depth from CM6's fold system
var foldDepths = _foldDepth(state, fl, ll, doc)
// Indent-unit width: measured or character-width fallback
var stepPx = this._stepPx
if (stepPx === null || stepPx <= 0)
stepPx = iw * (view.defaultCharacterWidth || 8)
// Highlight the active block (guide at cursor's deepest ancestor level)
var activeLvl
if (highlightActiveBlock) {
var cn = doc.lineAt(state.selection.main.head).number
if (cn >= bl && cn <= el) {
var cl = lvls[cn - bl]
var cfd = foldDepths[cn - fl] || 0
var cel = Math.max(cl, cfd)
if (cel > sa) activeLvl = cel - 1
}
}
var builder = new RangeSetBuilder()
for (var n = fl; n <= ll; n++) {
if (n < bl || n > el) continue
var lv = lvls[n - bl]
var fd = foldDepths[n - fl]
var effectiveLv = Math.max(lv, fd)
if (effectiveLv <= sa) continue
var parts = []
// Start from level 1 — level 0 (0 px) is never useful
var startL = Math.max(sa, 1)
for (var l = startL; l <= effectiveLv; l++) {
if (l > lv) break // cap at visual indent
var pos = Math.round(l * stepPx)
var cv = (activeLvl !== undefined && l === activeLvl)
? 'var(--oc-im-ca)' : 'var(--oc-im-c)'
parts.push('linear-gradient(' + cv + ',' + cv + ') ' + pos + 'px 0/' + thickness + 'px 100% no-repeat')
}
if (!parts.length) continue
var line = doc.line(n)
builder.add(line.from, line.from, Decoration.line({
class: 'cm-oc-im',
attributes: { style: '--oc-im:' + parts.join(',') }
}))
}
return builder.finish()
}
}, { decorations: v => v.decorations })
]
}
function topSearchExtension() {
return search({ top: true })
}
function placeholderExtension(text) {
return placeholder(text)
}
const mergeDefaultConfig = {
diffConfig: { scanLimit: 5000 },
gutter: true,
revertControls: "b-to-a",
collapseUnchanged: false,
}
// ============================================================
// Theme compartment — allows dynamic light/dark switching
// ============================================================
const themeCompartment = new Compartment
function themeExtension(isDark) {
return themeCompartment.of(isDark ? githubDark : githubLight)
}
function dispatchTheme(view, isDark) {
view.dispatch({
effects: themeCompartment.reconfigure(isDark ? githubDark : githubLight)
})
}
// ============================================================
// Fullscreen utility
// ============================================================
function getActiveEditor() {
var active = document.activeElement;
if (active && active.closest) {
var mw = active.closest('.cm-mergeView');
if (mw) return mw;
var ed = active.closest('.cm-editor');
if (ed) return ed;
}
return document.querySelector('.cm-editor') || null;
}
function toggleFullscreen(dom) {
if (!dom) return false;
if (dom.classList.contains('cm-fullscreen')) {
dom.classList.remove('cm-fullscreen');
dom.id = '';
return false;
} else {
dom.classList.add('cm-fullscreen');
dom.id = 'oc-fullscreen-active';
return true;
}
}
// ============================================================
// Theme observer — watch data-darkmode on <html> for all CM6 editors
// ============================================================
var _themeObserverInstalled = false;
function startThemeObserver() {
if (_themeObserverInstalled || typeof MutationObserver === 'undefined') return;
_themeObserverInstalled = true;
var observer = new MutationObserver(function() {
var theme = localStorage.getItem('oc-theme') || 'auto';
var isDark;
if (theme === 'dark') isDark = true;
else if (theme === 'light') isDark = false;
else isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
switchHljsTheme(isDark);
var editors = document.querySelectorAll('.cm-editor');
for (var i = 0; i < editors.length; i++) {
var view = editors[i].cmView && editors[i].cmView.view;
if (view) {
try { dispatchTheme(view, isDark); } catch(e) {}
}
}
});
observer.observe(document.body, { attributes: true, attributeFilter: ['data-darkmode'], subtree: true });
}
// ============================================================
// Markdown rendering (for debug log preview)
// ============================================================
var _hljsCSSInjected = false
function injectHljsCSS() {
if (_hljsCSSInjected) return
_hljsCSSInjected = true
var theme = localStorage.getItem('oc-theme') || 'auto'
var isDark
if (theme === 'dark') isDark = true
else if (theme === 'light') isDark = false
else isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
var style = document.createElement("style")
style.id = "hljs-theme"
style.textContent = isDark ? githubDarkCSS : githubLightCSS
document.head.appendChild(style)
}
function switchHljsTheme(isDark) {
if (!_hljsCSSInjected) { injectHljsCSS(); if (!_hljsCSSInjected) return }
var style = document.getElementById("hljs-theme")
if (style) style.textContent = isDark ? githubDarkCSS : githubLightCSS
}
function escapeHtml(s) {
return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;")
}
marked.use({
breaks: true,
gfm: true,
silent: true,
renderer: {
code: function(token) {
var lang = token.lang || ""
if (lang && hljs.getLanguage(lang)) {
injectHljsCSS()
var result = hljs.highlight(token.text, { language: lang, ignoreIllegals: true })
return '<pre><code class="hljs language-' + lang + '">' + result.value + '</code></pre>'
}
return '<pre><code>' + escapeHtml(token.text) + '</code></pre>'
}
}
})
function renderMarkdown(text) {
if (!text) return ''
try { return marked.parse(text) } catch(e) { return text }
}
export {
EditorView, EditorState, Compartment,
lineNumbers, highlightActiveLine, highlightActiveLineGutter,
highlightSpecialChars, drawSelection, dropCursor,
rectangularSelection, crosshairCursor, cmKeymap as keymap,
defaultKeymap, history, historyKeymap, indentWithTab,
toggleComment, foldKeymap,
syntaxHighlighting, HighlightStyle, bracketMatching,
foldGutter, indentOnInput, StreamLanguage, indentUnit,
yaml, markdown, shell, properties,
linter, lintGutter, yamlLinter,
search, searchKeymap, highlightSelectionMatches,
autocompletion, closeBrackets, closeBracketsKeymap,
snippetCompletion, mihomoCompletion,
githubDark, githubLight,
MergeView,
logLanguage, logHighlightStyle,
baseExtensions, placeholderExtension, indentMarkerExtension,
topSearchExtension, mergeDefaultConfig,
themeExtension, dispatchTheme,
startThemeObserver,
renderMarkdown,
getActiveEditor, toggleFullscreen
}
@@ -0,0 +1,30 @@
{
"name": "openclash-codemirror6",
"private": true,
"type": "module",
"_comment": "@codemirror/* packages are pinned to ~2025-11 versions (pre-tile-system) to avoid @codemirror/view TilePointer.advance() crash in merge view. DO NOT upgrade @codemirror/* unless the upstream tile.ts bug is confirmed fixed.",
"dependencies": {
"codemirror": "6.0.2",
"@codemirror/view": "6.38.8",
"@codemirror/state": "6.5.0",
"@codemirror/language": "6.11.2",
"@codemirror/commands": "6.8.0",
"@codemirror/search": "6.5.8",
"@codemirror/lint": "6.8.4",
"@codemirror/lang-yaml": "6.1.2",
"@codemirror/lang-markdown": "6.3.2",
"@codemirror/merge": "6.8.0",
"@codemirror/legacy-modes": "6.4.3",
"@codemirror/autocomplete": "6.18.6",
"@lezer/common": "1.2.3",
"@lezer/highlight": "1.2.1",
"@lezer/lr": "1.4.2",
"@fsegurai/codemirror-theme-bundle": "6.4.2",
"@babel/runtime": "8.0.0",
"js-yaml": "5.2.1",
"marked": "18.0.5",
"highlight.js": "11.11.1",
"esbuild": "0.28.1",
"lightningcss-cli": "1.32.0"
}
}
+7 -12
View File
@@ -157,16 +157,16 @@ Two rules of thumb that follow from prefix matching:
### Design Tokens
`src/media/_tokens.css` is **generated** — its header says "DO NOT EDIT". The source of truth is `.dev/tokens/`:
`src/media/_tokens.css` is **generated** — its header says "DO NOT EDIT". The source of truth is the standalone [`@eamonxg/aurora-tokens`](https://github.com/eamonxg/aurora-tokens) npm package, consumed here as a devDependency:
- **`defaults.js`** — the 10 editable input colors (`bg`, `surface`, `text`, `brand`, `on_brand`, `link`, `info`, `warning`, `success`, `danger`) for light and dark mode, as OKLCH strings.
- **`spec.js`** — `DERIVATIONS` (how every other token — `text_muted`, `surface_sunken`, `hairline`, `brand_hover`, `brand_subtle`, `focus_ring`, `progress_start`/`progress_end`, `*_surface`, `scrim`, `mega_menu_bg`, …) is computed from the inputs via `mix`/`shade`/`set`/`alpha`/`const` operators, and `FIXED` (mode-specific literals such as shadows that bypass derivation).
- **`engine.js`** — the OKLCH/OKLAB color math behind those operators, via [colorjs.io](https://colorjs.io/).
- **`resolve.js`** — `resolveMode(mode)` walks `DERIVATIONS` and returns a flat `{token: oklchString}` map with no `color-mix()`/`var()` left in it.
- **`resolve.js`** — `resolveMode(mode)` walks `DERIVATIONS` and returns a flat `{token: oklchString}` map with no `color-mix()`/`var()` left in it. `.dev/scripts/gen-tokens.js` imports `resolveMode`/`FIXED` straight from the package root.
**Changing a color:**
1. Edit `tokens/defaults.js` (base input colors) and/or `tokens/spec.js` (derivation rules, fixed literals).
1. Edit `spec.js`/`defaults.js` in the [`aurora-tokens`](https://github.com/eamonxg/aurora-tokens) repo (derivation rules, fixed literals, base input colors), tag a release so CI publishes the package, then bump the `@eamonxg/aurora-tokens` devDependency version here and run `npm install`. For unreleased iteration against a local checkout, run `npm link ../../aurora-tokens` from `.dev` instead of bumping/publishing.
2. Run `pnpm gen:tokens` (also runs automatically as part of `pnpm build`) to rewrite `src/media/_tokens.css` — it emits `:root` (light) and `[data-darkmode="true"]` (dark) blocks plus the `@theme inline` mapping, in that order.
3. Run `pnpm test` to check the color-math operators and derived-token invariants (`tests/engine.test.js`, `tests/resolve.test.js`, `tests/surfaces.test.js`) — e.g. hue families, lightness ordering between `bg`/`surface_sunken`/`surface`, and translucency of menu backgrounds.
@@ -226,7 +226,7 @@ htdocs/luci-static/
**Build Process:**
1. `pnpm gen:tokens` regenerates `src/media/_tokens.css` from `tokens/` (see [Design Tokens](#design-tokens))
1. `pnpm gen:tokens` regenerates `src/media/_tokens.css` from `@eamonxg/aurora-tokens` (see [Design Tokens](#design-tokens))
2. Vite builds the CSS entry points (`src/media/main.css` and `src/media/login.css`), keeping Tailwind's native `@layer` structure
3. Custom Vite plugin (`luci-js-compress`) minifies JS files via Terser
4. Static assets copied from `.dev/public/aurora/`
@@ -272,13 +272,13 @@ luci-theme-aurora/
│ │ └── images/ # Theme images + PWA icons
│ ├── scripts/ # Build scripts
│ │ ├── clean.js # Build cleanup utility
│ │ └── gen-tokens.js # Regenerates src/media/_tokens.css from tokens/
│ │ └── gen-tokens.js # Regenerates src/media/_tokens.css from @eamonxg/aurora-tokens
│ ├── src/ # Source code
│ │ ├── assets/icons/ # SVG icons
│ │ ├── media/ # CSS source (Tailwind CSS v4)
│ │ │ ├── main.css # Admin UI entry point (import manifest)
│ │ │ ├── login.css # Login page entry point
│ │ │ ├── _tokens.css # OKLCH theme tokens -- GENERATED, see tokens/
│ │ │ ├── _tokens.css # OKLCH theme tokens -- GENERATED, see @eamonxg/aurora-tokens
│ │ │ ├── _base.css # Document foundation (html/body viewport bg)
│ │ │ ├── _elements.css # Base element styles (headings, links, …)
│ │ │ ├── _layout.css # Page layout/structure
@@ -287,11 +287,6 @@ luci-theme-aurora/
│ │ │ └── patches/ # Per-page third-party patches (on-demand, one file per data-page)
│ │ └── resource/ # JavaScript resources
│ │ └── menu-aurora.js # Menu logic
│ ├── tokens/ # Design token source (-> src/media/_tokens.css)
│ │ ├── defaults.js # 10 editable input colors (light/dark)
│ │ ├── spec.js # Derivation rules (DERIVATIONS) + fixed literals
│ │ ├── engine.js # OKLCH/OKLAB color math (mix/shade/set/alpha)
│ │ └── resolve.js # Resolves spec into a flat token map
│ ├── tests/ # All test suites (pnpm test)
│ │ ├── engine.test.js # Color-math operators
│ │ ├── resolve.test.js # Resolved token invariants
@@ -336,7 +331,7 @@ luci-theme-aurora/
- **[Vite](https://vitejs.dev/)** - Build tool and development server
- **[pnpm](https://pnpm.io/)** - Fast, disk space efficient package manager
- **[lightningcss](https://lightningcss.dev/)** - CSS minifier
- **[colorjs.io](https://colorjs.io/)** - OKLCH/OKLAB color math for design token generation (`.dev/tokens/`)
- **[colorjs.io](https://colorjs.io/)** - OKLCH/OKLAB color math for design token generation (used by [`@eamonxg/aurora-tokens`](https://github.com/eamonxg/aurora-tokens))
- **[Terser](https://terser.org/)** - JavaScript minifier
- **[Prettier](https://prettier.io/)** - Code formatter
- **[prettier-plugin-tailwindcss](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)** - Tailwind class sorting
+1
View File
@@ -11,6 +11,7 @@
"test": "node --test tests/*.test.js"
},
"devDependencies": {
"@eamonxg/aurora-tokens": "^1.0.0",
"@tailwindcss/vite": "^4.1.11",
"@types/node": "^24.0.0",
"browserslist": "^4.28.2",
+2 -3
View File
@@ -1,7 +1,6 @@
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import { resolveMode } from "../tokens/resolve.js";
import { FIXED } from "../tokens/spec.js";
import { resolveMode, FIXED } from "@eamonxg/aurora-tokens";
const kebab = (s) => s.replace(/_/g, "-");
@@ -56,7 +55,7 @@ ${Object.keys(light)
const HEADER = `/**
* luci-theme-aurora: design tokens -- GENERATED, DO NOT EDIT.
* Run \`pnpm gen:tokens\`. Source: tokens/spec.js + tokens/defaults.js
* Run \`pnpm gen:tokens\`. Source: @eamonxg/aurora-tokens (spec.js + defaults.js)
* All color values are flat; lightningcss adds legacy fallbacks.
* ORDER MATTERS: [data-darkmode="true"] must stay after :root.
*/
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* luci-theme-aurora: design tokens -- GENERATED, DO NOT EDIT.
* Run `pnpm gen:tokens`. Source: tokens/spec.js + tokens/defaults.js
* Run `pnpm gen:tokens`. Source: @eamonxg/aurora-tokens (spec.js + defaults.js)
* All color values are flat; lightningcss adds legacy fallbacks.
* ORDER MATTERS: [data-darkmode="true"] must stay after :root.
*/
@@ -1,41 +0,0 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import Color from "colorjs.io";
import { mix, shade, set, alpha, konst, toOklch } from "../tokens/engine.js";
const l = (v) => new Color(toOklch(v)).to("oklch").coords[0];
const aOf = (v) => {
const c = new Color(toOklch(v));
return c.alpha;
};
test("mix: 50% white + black ≈ mid gray", () => {
const L = l(mix("white", "black", 0.5));
assert.ok(L > 0.4 && L < 0.6, `L=${L}`);
});
test("shade: lowers lightness by delta", () => {
const L = l(shade("oklch(0.5 0.1 200)", -0.1));
assert.ok(Math.abs(L - 0.4) < 0.02, `L=${L}`);
});
test("set: fixes L and C, keeps hue", () => {
const c = new Color(
toOklch(set("oklch(0.5 0.1 200)", 0.9, 0.05)),
).to("oklch");
assert.ok(Math.abs(c.coords[0] - 0.9) < 0.001);
assert.ok(Math.abs(c.coords[1] - 0.05) < 0.001);
assert.ok(Math.abs(c.coords[2] - 200) < 0.5);
});
test("alpha: sets opacity", () => {
assert.ok(
Math.abs(aOf(alpha("oklch(0.6 0.1 200)", 0.5)) - 0.5) < 0.001,
);
});
test("toOklch: serializes without color-mix/var", () => {
const s = toOklch(mix("oklch(0.68 0.11 233)", "white", 0.15));
assert.ok(s.startsWith("oklch("));
assert.ok(!s.includes("color-mix") && !s.includes("var("));
});
+1 -1
View File
@@ -1,6 +1,6 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { resolveMode } from "../tokens/resolve.js";
import { resolveMode } from "@eamonxg/aurora-tokens";
test("resolveMode(light) returns flat oklch for all tokens", () => {
const out = resolveMode("light");
@@ -2,7 +2,7 @@ import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import Color from "colorjs.io";
import { resolveMode } from "../tokens/resolve.js";
import { resolveMode } from "@eamonxg/aurora-tokens";
// [L, C, H] in oklch; alpha separate.
const lch = (s) => {
-27
View File
@@ -1,27 +0,0 @@
// 10 editable input defaults for light/dark, sourced from v2 (commit 3c4c67a).
export const DEFAULTS = {
light: {
bg: "oklch(0.967 0.003 264)",
surface: "oklch(1 0 0)",
text: "oklch(0.21 0.02 264)",
brand: "oklch(0.58 0.14 233)",
on_brand: "oklch(1 0 0)",
link: "oklch(0.74 0.238 322.16)",
info: "oklch(0.45 0.12 255)",
warning: "oklch(0.35 0.08 60)",
success: "oklch(0.32 0.09 165)",
danger: "oklch(0.35 0.12 25)",
},
dark: {
bg: "oklch(0.13 0.018 264)",
surface: "oklch(0.21 0.02 264)",
text: "oklch(0.985 0.002 264)",
brand: "oklch(0.6 0.13 188.745)",
on_brand: "oklch(1 0 0)",
link: "oklch(0.77 0.14 168)",
info: "oklch(0.8 0.11 255)",
warning: "oklch(0.82 0.13 80)",
success: "oklch(0.72 0.13 158)",
danger: "oklch(0.7 0.16 22)",
},
};
-32
View File
@@ -1,32 +0,0 @@
import Color from "colorjs.io";
const C = (v) => (v instanceof Color ? v : new Color(v));
// color-mix(in oklab, a p%, b) => position toward b is (1 - p)
export const mix = (a, b, p) =>
Color.mix(C(a), C(b), 1 - p, { space: "oklab", outputSpace: "oklch" });
export const shade = (a, dl) => {
const c = C(a).to("oklch");
c.coords[0] += dl;
return c;
};
export const set = (a, L, Ch) => {
const c = C(a).to("oklch");
c.coords[0] = L;
c.coords[1] = Ch;
return c;
};
export const alpha = (a, p) => {
const c = C(a).to("oklch");
c.alpha = p;
return c;
};
export const konst = (s) => C(s).to("oklch");
// Serialize a Color (or string) to an oklch() literal -- no color-mix / var().
export const toOklch = (v) =>
C(v).to("oklch").toString({ precision: 4, format: "oklch" });
-51
View File
@@ -1,51 +0,0 @@
import { DERIVATIONS } from "./spec.js";
import { DEFAULTS } from "./defaults.js";
import { mix, shade, set, alpha, konst, toOklch } from "./engine.js";
// inputs: {name: oklchString}. Returns flat {name: oklchString} values.
export function resolveTokens(mode, inputs) {
const derivs = DERIVATIONS[mode];
const resolved = { ...inputs };
const ref = (name) => {
if (resolved[name] === undefined) compute(name);
return resolved[name];
};
function compute(name) {
const rule = derivs[name];
if (!rule) throw new Error(`unknown derived token: ${name}`);
const [op, ...args] = rule;
let color;
switch (op) {
case "mix":
color = mix(ref(args[0]), ref(args[1]), args[2]);
break;
case "shade":
color = shade(ref(args[0]), args[1]);
break;
case "set":
color = set(ref(args[0]), args[1], args[2]);
break;
case "alpha":
color = alpha(ref(args[0]), args[1]);
break;
case "const":
if (args[0].startsWith("var:")) {
resolved[name] = ref(args[0].slice(4));
return;
}
color = konst(args[0]);
break;
default:
throw new Error(`unknown op: ${op}`);
}
resolved[name] = toOklch(color);
}
for (const name of Object.keys(derivs)) compute(name);
return resolved;
}
export const resolveMode = (mode) =>
resolveTokens(mode, { ...DEFAULTS[mode] });
-83
View File
@@ -1,83 +0,0 @@
// Operators: ['mix',a,b,p] ['shade',a,dl] ['set',a,L,C]
// ['alpha',a,p] ['const',str]
export const DERIVATIONS = {
light: {
text_muted: ["mix", "text", "bg", 0.62],
text_subtle: ["mix", "text", "bg", 0.48],
surface_sunken: ["shade", "bg", -0.012],
surface_overlay: ["shade", "bg", 0.016],
hairline: ["alpha", "text", 0.13],
hover_faint: ["shade", "bg", -0.04],
brand_hover: ["shade", "brand", -0.06],
brand_subtle: ["mix", "brand", "bg", 0.12],
brand_subtle_hover: ["shade", "brand_subtle", -0.04],
focus_ring: ["alpha", "brand", 0.6],
progress_start: ["mix", "brand", "surface_sunken", 0.65],
progress_end: ["const", "var:brand"],
info_surface: ["set", "info", 0.94, 0.05],
warning_surface: ["set", "warning", 0.95, 0.05],
success_surface: ["set", "success", 0.94, 0.05],
danger_surface: ["set", "danger", 0.94, 0.05],
danger_surface_hover: ["shade", "danger_surface", -0.04],
scrim: ["const", "oklch(0 0 0 / 0.6)"],
// Fully opaque: a clean solid panel (Apple's #fafafc). Any translucency let
// the dimmed curtain bleed through, greying the panel off the header tone
// and leaking faint blurred page content into the empty columns. The header
// lifts to this same colour when the menu opens (see _layout.css) so bar and
// panel read as one continuous surface.
mega_menu_bg: ["alpha", "surface_overlay", 1],
// Mega-menu curtain: a real dimming layer. A near-page-light grey (the
// earlier #e8e8ed attempt) only blurred without darkening, so the mask read
// as absent. Black at a modest alpha actually dims the page; the now-opaque
// panel + its shadow give a clean edge, so this no longer bands the way the
// old translucent panel over a heavy scrim did. Lighter than the 0.6 modal
// scrim — it's a menu backdrop, not a dialog.
mega_menu_scrim: ["const", "oklch(0 0 0 / 0.32)"],
},
dark: {
text_muted: ["mix", "text", "bg", 0.62],
text_subtle: ["mix", "text", "bg", 0.42],
surface_sunken: ["shade", "surface", -0.045],
surface_overlay: ["shade", "surface", 0.02],
hairline: ["alpha", "text", 0.1],
hover_faint: ["alpha", "text", 0.05],
brand_hover: ["shade", "brand", -0.05],
brand_subtle: ["mix", "brand", "bg", 0.16],
brand_subtle_hover: ["shade", "brand_subtle", 0.04],
focus_ring: ["alpha", "brand", 0.6],
// Derived from brand like light — not hardcoded — so the bar tracks the
// active brand colour instead of a frozen teal.
progress_start: ["mix", "brand", "surface_sunken", 0.65],
progress_end: ["const", "var:brand"],
info_surface: ["set", "info", 0.32, 0.05],
warning_surface: ["set", "warning", 0.33, 0.06],
success_surface: ["set", "success", 0.3, 0.05],
danger_surface: ["set", "danger", 0.32, 0.08],
danger_surface_hover: ["shade", "danger_surface", 0.04],
scrim: ["const", "oklch(0 0 0 / 0.6)"],
// Deeper than surface_overlay (23%): surface_sunken (16.5%) tracks Apple's
// opened-panel #161617 (~18.5%). Fully opaque — a clean solid panel with no
// curtain bleed; the header lifts to this colour on open (see _layout.css)
// so bar and panel are one continuous surface.
mega_menu_bg: ["alpha", "surface_sunken", 1],
// Dark curtain stays a near-black dim (Apple's rgba(0,0,0,.4)); the dark
// panel and dark page already share a tone, so this only needs to deepen.
mega_menu_scrim: ["const", "oklch(0 0 0 / 0.5)"],
},
};
// Fixed mode-specific literals, emitted verbatim rather than derived.
export const FIXED = {
light: {
app_shadow_sm:
"0 1px 3px oklch(0 0 0 / 0.06), 0 1px 2px oklch(0 0 0 / 0.04)",
app_shadow_md:
"0 4px 16px oklch(0 0 0 / 0.08), 0 1px 3px oklch(0 0 0 / 0.04)",
app_shadow_lg: "0 12px 32px oklch(0 0 0 / 0.12)",
},
dark: {
app_shadow_sm: "0 4px 12px oklch(0 0 0 / 0.3)",
app_shadow_md: "0 10px 28px oklch(0 0 0 / 0.42)",
app_shadow_lg: "0 20px 48px oklch(0 0 0 / 0.55)",
},
};
+169 -207
View File
@@ -12,7 +12,13 @@ import { browserslistToTargets } from "lightningcss";
import { basename, dirname, join, relative, resolve } from "path";
import { minify as terserMinify } from "terser";
import { promisify } from "util";
import { defineConfig, loadEnv, Plugin, ResolvedConfig } from "vite";
import {
defineConfig,
loadEnv,
Plugin,
ResolvedConfig,
ViteDevServer,
} from "vite";
const execAsync = promisify(exec);
@@ -20,66 +26,38 @@ const CURRENT_DIR = process.cwd();
const PROJECT_ROOT = resolve(CURRENT_DIR, "..");
const BUILD_OUTPUT = resolve(PROJECT_ROOT, "htdocs/luci-static");
async function scanFiles(
dir: string,
extensions: string[] = [],
): Promise<string[]> {
const entries = await readdir(dir, { withFileTypes: true });
const files: string[] = [];
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await scanFiles(fullPath, extensions)));
} else if (
entry.isFile() &&
(!extensions.length || extensions.some((ext) => fullPath.endsWith(ext)))
) {
files.push(fullPath);
}
}
return files;
}
function createLuciJsCompressPlugin(): Plugin {
let outDir: string;
let jsFiles: string[] = [];
return {
name: "luci-js-compress",
apply: "build",
configResolved(config: ResolvedConfig) {
outDir = config.build.outDir;
},
async buildStart() {
const srcDir = resolve(CURRENT_DIR, "src/resource");
jsFiles = await scanFiles(srcDir, [".js"]);
},
async generateBundle() {
const srcDir = resolve(CURRENT_DIR, "src/resource");
const jsFiles = (await readdir(srcDir, { recursive: true })).filter(
(f) => f.endsWith(".js"),
);
await Promise.all(
jsFiles.map(async (filePath) => {
jsFiles.map(async (relPath) => {
const normalized = relPath.replace(/\\/g, "/");
try {
const sourceCode = await readFile(filePath, "utf-8");
const sourceCode = await readFile(join(srcDir, relPath), "utf-8");
const compressed = await terserMinify(sourceCode, {
parse: { bare_returns: true },
compress: false,
mangle: false,
format: { comments: false, beautify: false },
});
const relativePath = relative(
resolve(CURRENT_DIR, "src/resource"),
filePath,
).replace(/\\/g, "/");
const outputPath = join(outDir, "resources", relativePath);
const outputPath = join(outDir, "resources", normalized);
await mkdir(dirname(outputPath), { recursive: true });
await writeFile(outputPath, compressed.code || sourceCode, "utf-8");
} catch (error: any) {
console.error(`JS compress failed: ${filePath}`, error?.message);
console.error(
`${tag("JS Compress")} src/resource/${normalized}: ${error?.message}`,
);
}
}),
);
@@ -87,16 +65,6 @@ function createLuciJsCompressPlugin(): Plugin {
};
}
interface RouteConfig {
routes: Record<string, string>;
hmrMessage: string;
}
interface ResourceConfig {
css: RouteConfig;
js: RouteConfig;
}
// On-demand third-party patches: serve src/media/patches/<page>.css at
// /luci-static/aurora/patches/<page>.css in dev. Without this, header.ut's patch
// <link> falls through to the OpenWrt proxy (404 / stale router asset) and patch
@@ -106,107 +74,79 @@ const PATCH_PUBLIC_PREFIX = "/luci-static/aurora/patches/";
const PATCH_SRC_DIR = resolve(CURRENT_DIR, "src/media/patches");
function createLocalServePlugin(): Plugin {
const resourceConfig: ResourceConfig = {
css: {
routes: {
"/luci-static/aurora/main.css": "/src/media/main.css",
"/luci-static/aurora/login.css": "/src/media/login.css",
},
hmrMessage: "CSS file changed",
},
js: {
routes: {
"/luci-static/resources/view/aurora/sysauth.js":
"src/resource/view/aurora/sysauth.js",
"/luci-static/resources/menu-aurora.js": "src/resource/menu-aurora.js",
},
hmrMessage: "JS file changed",
},
const cssRoutes: Record<string, string> = {
"/luci-static/aurora/main.css": "/src/media/main.css",
"/luci-static/aurora/login.css": "/src/media/login.css",
};
const jsRoutes: Record<string, string> = {
"/luci-static/resources/view/aurora/sysauth.js":
"src/resource/view/aurora/sysauth.js",
"/luci-static/resources/menu-aurora.js": "src/resource/menu-aurora.js",
};
const buildHmrMap = (routes: Record<string, string>, isVitePath: boolean) => {
const map: Record<string, string> = {};
Object.entries(routes).forEach(([publicPath, sourcePath]) => {
const filePath = isVitePath
? resolve(CURRENT_DIR, sourcePath.replace(/^\//, ""))
: resolve(CURRENT_DIR, sourcePath);
map[filePath.replace(/\\/g, "/")] = publicPath;
});
return map;
};
const cssHmrMap = buildHmrMap(resourceConfig.css.routes, true);
const jsHmrMap = buildHmrMap(resourceConfig.js.routes, false);
// Any theme CSS (entries, partials, patches) or served JS change must force
// a full reload: proxied LuCI pages link /luci-static/... URLs, so Vite's
// granular css-update never matches them and would silently do nothing.
const MEDIA_SRC_DIR = resolve(CURRENT_DIR, "src/media").replace(/\\/g, "/");
const reloadJsFiles = new Set(
Object.values(jsRoutes).map((src) =>
resolve(CURRENT_DIR, src).replace(/\\/g, "/"),
),
);
return {
name: "local-serve-plugin",
apply: "serve",
enforce: "pre",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
if (!req.url) return next();
const [pathname, search] = req.url.split("?");
const cssTarget = resourceConfig.css.routes[pathname];
const cssTarget = cssRoutes[pathname];
if (cssTarget) {
req.url = cssTarget + (search ? `?${search}` : "");
return next();
}
if (pathname.startsWith(PATCH_PUBLIC_PREFIX) && pathname.endsWith(".css")) {
if (
pathname.startsWith(PATCH_PUBLIC_PREFIX) &&
pathname.endsWith(".css")
) {
const file = basename(pathname);
if (existsSync(join(PATCH_SRC_DIR, file))) {
req.url = `/src/media/patches/${file}` + (search ? `?${search}` : "");
req.url =
`/src/media/patches/${file}` + (search ? `?${search}` : "");
return next();
}
}
const jsPath = resourceConfig.js.routes[pathname];
const jsPath = jsRoutes[pathname];
if (jsPath) {
try {
const file = resolve(CURRENT_DIR, jsPath);
const code = await readFile(file, "utf-8");
const code = await readFile(resolve(CURRENT_DIR, jsPath), "utf-8");
res.setHeader("Content-Type", "text/javascript");
res.setHeader("Cache-Control", "no-store");
res.statusCode = 200;
res.end(code);
return;
} catch (err) {
console.error(`[JS Error] Failed to read ${jsPath}:`, err);
} catch (err: any) {
console.error(
`${tag("Serve")} ${pathname} → cannot read ${jsPath}: ${err?.message ?? err}`,
);
}
}
next();
});
},
handleHotUpdate({ file, server }) {
const normalizedFile = file.replace(/\\/g, "/");
if (
normalizedFile.startsWith(PATCH_SRC_DIR.replace(/\\/g, "/") + "/") &&
normalizedFile.endsWith(".css")
) {
console.log(`[HMR] Patch CSS changed: ${basename(normalizedFile)}`);
const nf = file.replace(/\\/g, "/");
const isThemeCss =
nf.startsWith(MEDIA_SRC_DIR + "/") && nf.endsWith(".css");
if (isThemeCss || reloadJsFiles.has(nf)) {
console.log(
`${tag("Serve")} ${relative(CURRENT_DIR, file)} → full reload`,
);
server.ws.send({ type: "full-reload", path: "*" });
return [];
}
const resources = [
{ map: cssHmrMap, config: resourceConfig.css },
{ map: jsHmrMap, config: resourceConfig.js },
];
for (const { map, config } of resources) {
const publicPath = map[normalizedFile];
if (publicPath) {
console.log(`[HMR] ${config.hmrMessage}: ${publicPath} (tracked: ${normalizedFile})`);
server.ws.send({ type: "full-reload", path: "*" });
return [];
}
}
},
};
}
@@ -215,35 +155,55 @@ const UT_TEMPLATE_DIR = resolve(PROJECT_ROOT, "ucode/template/themes/aurora");
const UT_REMOTE_DIR = "/usr/share/ucode/luci/template/themes/aurora";
// Key selection is ssh's own job: ssh-agent or a Host block in ~/.ssh/config.
const SSH_ARGS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
// ConnectTimeout applies to every ssh call: template pushes gate /cgi-bin page
// loads, so an unreachable device must fail fast instead of hanging them.
const SSH_ARGS =
"-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5";
function parseHost(sshHost: string): string {
const atIndex = sshHost.lastIndexOf("@");
return atIndex !== -1 ? sshHost.slice(atIndex + 1) : sshHost;
function tag(name: string): string {
return `${new Date().toLocaleTimeString("en-US")} [${name}]`;
}
const utTag = () => tag("UT Sync");
const parseHost = (sshHost: string): string => sshHost.split("@").pop()!;
function reportSshError(err: any, sshHost: string): void {
const host = parseHost(sshHost);
const stderr = err?.stderr || err?.message || "";
if (stderr.includes("Host key verification failed") || stderr.includes("REMOTE HOST IDENTIFICATION HAS CHANGED")) {
console.error(`\n[UT Sync] SSH host key mismatch for ${host}.`);
console.error(`[UT Sync] The device may have been reflashed. Run this to fix:\n`);
if (
stderr.includes("Host key verification failed") ||
stderr.includes("REMOTE HOST IDENTIFICATION HAS CHANGED")
) {
console.error(`\n${utTag()} SSH host key mismatch for ${host}.`);
console.error(`${utTag()} The device may have been reflashed. Run:\n`);
console.error(` ssh-keygen -R ${host}\n`);
} else if (stderr.includes("Permission denied") || stderr.includes("Authentication failed")) {
console.error(`\n[UT Sync] SSH authentication failed for ${sshHost}.`);
console.error(`[UT Sync] Run \`pnpm setup\` to configure passwordless login.\n`);
} else if (stderr.includes("Connection refused") || stderr.includes("Connection timed out") || stderr.includes("No route to host")) {
console.error(`\n[UT Sync] Cannot reach ${host}. Check that the device is online and SSH is enabled.\n`);
} else if (
stderr.includes("Permission denied") ||
stderr.includes("Authentication failed")
) {
console.error(`\n${utTag()} SSH authentication failed for ${sshHost}.`);
console.error(
`${utTag()} Run \`pnpm setup\` to configure passwordless login.\n`,
);
} else if (
stderr.includes("Connection refused") ||
stderr.includes("Connection timed out") ||
stderr.includes("No route to host")
) {
console.error(
`\n${utTag()} Cannot reach ${host}. Check that the device is online and SSH is enabled.\n`,
);
} else {
console.error(`\n[UT Sync] SSH connection failed: ${stderr}\n`);
console.error(`\n${utTag()} SSH connection failed: ${stderr}\n`);
}
}
async function checkSshConnection(sshHost: string): Promise<boolean> {
try {
await execAsync(`ssh ${SSH_ARGS} -o ConnectTimeout=5 "${sshHost}" echo ok`);
console.log(`[UT Sync] SSH connection verified.`);
await execAsync(`ssh ${SSH_ARGS} "${sshHost}" echo ok`);
console.log(`${utTag()} SSH connection to ${sshHost} verified.`);
return true;
} catch (err: any) {
reportSshError(err, sshHost);
@@ -255,25 +215,37 @@ function createUtSyncPlugin(sshHost: string): Plugin {
let dirty = false;
let flushing: Promise<void> | null = null;
let timer: ReturnType<typeof setTimeout> | null = null;
// Filenames whose change events triggered the pending sync — the push itself
// is always the whole directory, this only makes the log say what changed.
const pending = new Set<string>();
// The templates are tiny (3 files), so every sync just pushes the whole
// directory in one tarball streamed over ssh stdin — OpenSSH 9+ scp defaults
// to the SFTP protocol, which Dropbear on OpenWrt does not ship a server for.
// The templates are tiny, so every sync just pushes the whole directory in
// one tarball streamed over ssh stdin — OpenSSH 9+ scp defaults to the SFTP
// protocol, which Dropbear on OpenWrt does not ship a server for. Note the
// tar extract only adds/overwrites: deleting or renaming a local .ut leaves
// the old file on the device until a reinstall or manual cleanup.
const pushAll = () =>
execAsync(
`tar -C "${UT_TEMPLATE_DIR}" -cf - . | ssh ${SSH_ARGS} "${sshHost}" "mkdir -p '${UT_REMOTE_DIR}' && tar -xf - -C '${UT_REMOTE_DIR}'"`,
);
const flush = (server: any): Promise<void> => {
const flush = (server: ViteDevServer): Promise<void> => {
if (!flushing) {
flushing = (async () => {
while (dirty) {
dirty = false;
const files = [...pending];
pending.clear();
const started = Date.now();
try {
await pushAll();
console.log(`[UT Sync] Templates synced to ${sshHost}.`);
const what = files.length ? files.join(", ") : "all templates";
console.log(
`${utTag()} ${what} → ${sshHost} (${Date.now() - started}ms)`,
);
server.ws.send({ type: "full-reload", path: "*" });
} catch (err: any) {
files.forEach((f) => pending.add(f));
reportSshError(err, sshHost);
break;
}
@@ -284,7 +256,7 @@ function createUtSyncPlugin(sshHost: string): Plugin {
return flushing;
};
const markDirty = (server: any) => {
const markDirty = (server: ViteDevServer) => {
dirty = true;
if (timer) clearTimeout(timer);
timer = setTimeout(() => flush(server), 150);
@@ -293,10 +265,10 @@ function createUtSyncPlugin(sshHost: string): Plugin {
return {
name: "ut-sync-plugin",
apply: "serve",
configureServer(server) {
console.log(`[UT Sync] Watching ${UT_TEMPLATE_DIR}`);
console.log(`[UT Sync] Target: ${sshHost}:${UT_REMOTE_DIR}`);
console.log(
`${utTag()} ${relative(PROJECT_ROOT, UT_TEMPLATE_DIR)}/*.ut → ${sshHost}:${UT_REMOTE_DIR}`,
);
// Full push on startup so edits made while the server was down (or a
// freshly flashed device) can't leave the router stale.
@@ -307,6 +279,7 @@ function createUtSyncPlugin(sshHost: string): Plugin {
server.watcher.add(UT_TEMPLATE_DIR);
const onTemplateEvent = (file: string) => {
if (file.startsWith(UT_TEMPLATE_DIR) && file.endsWith(".ut")) {
pending.add(basename(file));
markDirty(server);
}
};
@@ -320,6 +293,7 @@ function createUtSyncPlugin(sshHost: string): Plugin {
return next();
}
if (timer) clearTimeout(timer);
console.log(`${utTag()} Holding ${req.url} until templates sync…`);
flush(server).then(
() => next(),
() => next(),
@@ -333,7 +307,6 @@ function createRedirectPlugin(): Plugin {
return {
name: "redirect-plugin",
apply: "serve",
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (req.url === "/" || req.url === "/index.html") {
@@ -348,7 +321,7 @@ function createRedirectPlugin(): Plugin {
}
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, CURRENT_DIR, "");
const env = loadEnv(mode, CURRENT_DIR);
// VITE_OPENWRT_HOST is just the router address — a bare IP/hostname like
// 192.168.1.1 (host:port and http:// URL forms also work). The web proxy
// target and the .ut-sync ssh target are both derived from it; ssh key
@@ -362,60 +335,6 @@ export default defineConfig(({ mode }) => {
const DEV_HOST = env.VITE_DEV_HOST || "127.0.0.1";
const DEV_PORT = Number(env.VITE_DEV_PORT) || 5173;
const proxyConfig = {
"/luci-static": {
target: OPENWRT_URL,
changeOrigin: true,
secure: false,
},
"/cgi-bin": {
target: OPENWRT_URL,
changeOrigin: true,
secure: false,
configure: (proxy: any) => {
// Force an uncompressed upstream response: the HTML injection below
// treats the body as UTF-8 text and would corrupt a gzipped payload.
proxy.on("proxyReq", (proxyReq: any) => {
proxyReq.removeHeader("accept-encoding");
});
proxy.on("proxyRes", (proxyRes: any, req: any, res: any) => {
const contentType = proxyRes.headers["content-type"] || "";
if (contentType.includes("text/html")) {
const chunks: Buffer[] = [];
proxyRes.on("data", (chunk: Buffer) => {
chunks.push(chunk);
});
proxyRes.on("end", () => {
let html = Buffer.concat(chunks).toString("utf-8");
const viteClient = `<script type="module" src="/@vite/client"></script>`;
if (html.includes("</head>") && !html.includes("/@vite/client")) {
html = html.replace("</head>", `${viteClient}\n\t</head>`);
console.log("[HMR] Injected Vite client into proxied HTML");
}
res.removeAllListeners("end");
res.setHeader("Content-Length", Buffer.byteLength(html));
res.end(html);
});
proxyRes.pipe = () => proxyRes;
}
});
},
},
} as const;
const aliasConfig = {
"@": resolve(CURRENT_DIR, "src"),
"@assets": resolve(CURRENT_DIR, "src/assets"),
} as const;
return {
plugins: [
tailwindcss(),
@@ -424,7 +343,6 @@ export default defineConfig(({ mode }) => {
createUtSyncPlugin(OPENWRT_SSH_HOST),
createLuciJsCompressPlugin(),
],
css: {
lightningcss: {
targets: browserslistToTargets(
@@ -432,7 +350,6 @@ export default defineConfig(({ mode }) => {
),
},
},
build: {
outDir: BUILD_OUTPUT,
emptyOutDir: false,
@@ -445,7 +362,7 @@ export default defineConfig(({ mode }) => {
// aurora/patches/<page>.css (the `patches/` key prefix lands them there
// via assetFileNames below). header.ut links the matching one per page.
...Object.fromEntries(
readdirSync(PATCH_SRC_DIR)
(existsSync(PATCH_SRC_DIR) ? readdirSync(PATCH_SRC_DIR) : [])
.filter((f) => f.endsWith(".css"))
.map((f) => [
`patches/${f.slice(0, -4)}`,
@@ -453,23 +370,68 @@ export default defineConfig(({ mode }) => {
]),
),
},
output: {
assetFileNames: "aurora/[name].[ext]",
},
output: { assetFileNames: "aurora/[name].[ext]" },
},
},
server: {
host: DEV_HOST,
port: DEV_PORT,
proxy: proxyConfig,
headers: {
"Cache-Control": "no-store",
proxy: {
"/luci-static": {
target: OPENWRT_URL,
changeOrigin: true,
secure: false,
},
"/cgi-bin": {
target: OPENWRT_URL,
changeOrigin: true,
secure: false,
// We write every response ourselves in `proxyRes` below, so the Vite
// client can be injected into proxied LuCI HTML.
selfHandleResponse: true,
configure: (proxy) => {
// Force an uncompressed upstream response: the HTML injection below
// treats the body as UTF-8 text and would corrupt a gzipped payload.
proxy.on("proxyReq", (proxyReq) => {
proxyReq.removeHeader("accept-encoding");
});
proxy.on("proxyRes", (proxyRes, req, res) => {
const status = proxyRes.statusCode ?? 200;
const ct = proxyRes.headers["content-type"] || "";
if (!ct.includes("text/html")) {
res.writeHead(status, proxyRes.headers);
proxyRes.pipe(res);
return;
}
const chunks: Buffer[] = [];
proxyRes.on("data", (c: Buffer) => chunks.push(c));
proxyRes.on("end", () => {
let html = Buffer.concat(chunks).toString("utf-8");
const client = `<script type="module" src="/@vite/client"></script>`;
if (
html.includes("</head>") &&
!html.includes("/@vite/client")
) {
html = html.replace("</head>", `${client}\n\t</head>`);
}
const { "transfer-encoding": _, ...headers } = proxyRes.headers;
res.writeHead(status, {
...headers,
"content-length": Buffer.byteLength(html),
});
res.end(html);
});
});
},
},
},
headers: { "Cache-Control": "no-store" },
},
resolve: {
alias: aliasConfig,
alias: {
"@": resolve(CURRENT_DIR, "src"),
"@assets": resolve(CURRENT_DIR, "src/assets"),
},
},
};
});
+1 -1
View File
@@ -9,7 +9,7 @@ LUCI_TITLE:=Aurora Theme (A modern browser theme built with Vite and Tailwind CS
LUCI_DEPENDS:=+luci-base
PKG_VERSION:=1.0.8
PKG_RELEASE:=43
PKG_RELEASE:=44
PKG_LICENSE:=Apache-2.0
LUCI_MINIFY_CSS:=
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-tracking:initial}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-widest:.1em;--radius-sm:calc(var(--radius-base)*.25);--radius-md:calc(var(--radius-base)*.75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base)*1.5);--radius-2xl:calc(var(--radius-base)*2);--radius-3xl:calc(var(--radius-base)*3);--radius-4xl:calc(var(--radius-base)*4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--animate-spin:spin 1s linear infinite;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base)*.5);--container-max-width:var(--container-max-width)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;backgrLine truncated
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-tracking:initial}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-widest:.1em;--radius-sm:calc(var(--radius-base) * .25);--radius-md:calc(var(--radius-base) * .75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base) * 1.5);--radius-2xl:calc(var(--radius-base) * 2);--radius-3xl:calc(var(--radius-base) * 3);--radius-4xl:calc(var(--radius-base) * 4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--animate-spin:spin 1s linear infinite;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base) * .5);--container-max-width:var(--container-max-width)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacinLine truncated
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--tw-leading:initial;--tw-tracking:initial;--tw-ease:initial;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-xs:20rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius-base)*.25);--radius-md:calc(var(--radius-base)*.75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base)*1.5);--radius-2xl:calc(var(--radius-base)*2);--radius-3xl:calc(var(--radius-base)*3);--radius-4xl:calc(var(--radius-base)*4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--blur-md:12px;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base)*.5);--container-max-width:var(--container-max-width)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);fonLine truncated
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--tw-scrollbar-thumb:#0000;--tw-scrollbar-track:#0000;--tw-leading:initial;--tw-tracking:initial;--tw-ease:initial;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-border-spacing-x:0;--tw-border-spacing-y:0}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:var(--spacing);--container-xs:20rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius-base) * .25);--radius-md:calc(var(--radius-base) * .75);--radius-lg:var(--radius-base);--radius-xl:calc(var(--radius-base) * 1.5);--radius-2xl:calc(var(--radius-base) * 2);--radius-3xl:calc(var(--radius-base) * 3);--radius-4xl:calc(var(--radius-base) * 4);--shadow-sm:var(--app-shadow-sm);--shadow-md:var(--app-shadow-md);--shadow-lg:var(--app-shadow-md);--shadow-xl:var(--app-shadow-lg);--shadow-2xl:var(--app-shadow-lg);--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-md:12px;--blur-lg:16px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius:calc(var(--radius-base) * .5);--container-max-width:var(--container-max-width)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-familyLine truncated
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg.tr{border-radius:0}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg{background-color:var(--surface-overlay)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg:not(.tr){border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}@media (hover:hover){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg:not(.tr):hover{border-color:var(--hairline);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg{background-color:var(--surface-overlay)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg:not(.tr){border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline)}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg span:where([data-darkmode=true],[data-darkmode=true] *),[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg td:where([data-darkmode=true],[data-darkmode=true] *),[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg th:where([data-darkmode=true],[data-darkmode=true] *){color:var(--text)!important}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg img[src*=\.svg]:where([data-darkmode=true],[data-darkmode=true] *){--tw-invert:invert(100%);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .td{padding-block:calc(var(--spacing)*2)}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .td{padding-block:calc(var(--spacing)*1)}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .th{padding-block:calc(var(--spacing)*2)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist){margin-bottom:calc(var(--spacing)*0);border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);background-color:#0000;border-width:0;border-radius:0}@media (hover:hover){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) tr:hover{background-color:#0000}}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) tr{border-style:var(--tw-border-style);padding-inline:calc(var(--spacing)*0);padding-block:calc(var(--spacing)*0);border-width:0;display:table-row}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) td{border-style:var(--tw-border-style);padding-inline:calc(var(--spacing)*0);padding-block:calc(var(--spacing)*.5);border-width:0}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) td{display:table-cell}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) td:first-child{padding-right:calc(var(--spacing)*2);white-space:nowrap;opacity:.7}[data-page=admin-dashboard] .Dashboard>.section-content .title h3{border-style:var(--tw-border-style);padding-bottom:calc(var(--spacing)*4);color:var(--text);border-width:0}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .title h3{margin-inline:calc(var(--spacing)*0);padding-bottom:calc(var(--spacing)*2)}}[data-page=admin-dashboard] .Dashboard>.section-content .router-status-wifi .wifi-info .devices-info .tr .td:nth-child(3){top:calc(var(--spacing)*0);width:10Line truncated
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg.tr{border-radius:0}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg{background-color:var(--surface-overlay)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg:not(.tr){border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline);--tw-shadow:var(--app-shadow-md);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (hover:hover){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg:not(.tr):hover{border-color:var(--hairline);--tw-shadow:var(--app-shadow-lg);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg{background-color:var(--surface-overlay)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg:not(.tr){border-style:var(--tw-border-style);border-width:1px;border-color:var(--hairline)}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg span:where([data-darkmode=true],[data-darkmode=true] *),[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg td:where([data-darkmode=true],[data-darkmode=true] *),[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg th:where([data-darkmode=true],[data-darkmode=true] *){color:var(--text)!important}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg img[src*=\.svg]:where([data-darkmode=true],[data-darkmode=true] *){--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .td{padding-block:calc(var(--spacing) * 2)}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .td{padding-block:var(--spacing)}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .th{padding-block:calc(var(--spacing) * 2)}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist){border-style:var(--tw-border-style);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;border-width:0;border-radius:0;margin-bottom:0}@media (hover:hover){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) tr:hover{background-color:#0000}}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) tr{border-style:var(--tw-border-style);border-width:0;padding-block:0;padding-inline:0;display:table-row}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) td{border-style:var(--tw-border-style);padding-inline:0;padding-block:calc(var(--spacing) * .5);border-width:0}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) td{display:table-cell}}[data-page=admin-dashboard] .Dashboard>.section-content .dashboard-bg .table:not(.assoclist) td:first-child{padding-right:calc(var(--spacing) * 2);white-space:nowrap;opacity:.7}[data-page=admin-dashboard] .Dashboard>.section-content .title h3{border-style:var(--tw-border-style);padding-bottom:calc(var(--spacing) * 4);color:var(--text);border-width:0}@media not all and (min-width:48rem){[data-page=admin-dashboard] .Dashboard>.section-content .title h3{padding-bottom:calc(var(--spacing) * 2);margin-inline:0}}[data-page=admin-dashboard] .Dashboard>.section-content .router-status-wifi .wifi-info .devices-info .tr .td:nth-child(3){width:100%;padding-inline:0;position:relative;top:0}@media not all and (min-width:48rem){[data-page=admin-dashboard]Line truncated
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
[data-page=admin-modem-modemdata-modempreview] .ifacebox-body .ifacebadge{width:auto!important}
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@media not all and (min-width:48rem){[data-name=bridge-vlan]>div{overflow:visible!important}}
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
[data-page=admin-services-openclash-config] .sub_div img{height:calc(var(--spacing)*5);width:calc(var(--spacing)*5)}
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
[data-page=admin-services-openclash-config] .sub_div img{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5)}
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
@media not all and (min-width:48rem){[data-page=admin-services-openclash-settings] .cbi-value-field .cbi-input-select{width:100%!important}[data-page=admin-services-openclash-settings] .diag-style{gap:calc(var(--spacing)*4);grid-template-columns:repeat(1,minmax(0,1fr));display:grid}}[data-page=admin-services-openclash-settings] .diag-style>div{align-items:center;gap:calc(var(--spacing)*2);flex-direction:column;display:flex}@media not all and (min-width:48rem){[data-page=admin-services-openclash-settings] .diag-style>div{gap:calc(var(--spacing)*1);width:100%!important}}
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@media not all and (min-width:48rem){[data-page=admin-services-openclash-settings] .cbi-value-field .cbi-input-select{width:100%!important}[data-page=admin-services-openclash-settings] .diag-style{gap:calc(var(--spacing) * 4);grid-template-columns:repeat(1,minmax(0,1fr));display:grid}}[data-page=admin-services-openclash-settings] .diag-style>div{align-items:center;gap:calc(var(--spacing) * 2);flex-direction:column;display:flex}@media not all and (min-width:48rem){[data-page=admin-services-openclash-settings] .diag-style>div{gap:var(--spacing);width:100%!important}}
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}[data-page=admin-statistics-graphs] [data-plugin] img:where([data-darkmode=true],[data-darkmode=true] *){--tw-hue-rotate:hue-rotate(150deg);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,);--tw-invert:invert(100%)}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}[data-page=admin-statistics-graphs] [data-plugin] img:where([data-darkmode=true],[data-darkmode=true] *){--tw-hue-rotate:hue-rotate(150deg);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);--tw-invert:invert(100%)}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
@@ -1,2 +1,2 @@
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid}}}[data-page=admin-system-filemanager] #file-manager-container{overflow:auto}[data-page=admin-system-filemanager] #file-manager-container #status-bar{border-style:var(--tw-border-style);background-color:var(--surface);border-width:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow
PKG_VERSION:=20260531
PKG_RELEASE:=37
PKG_RELEASE:=38
PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=5430b3312cd783ba2179a24297979252c0463bb9
PKG_SOURCE_VERSION:=9f08f8385d8208dabd420736bd374efe3a22597c
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0
+2 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=sing-box
PKG_VERSION:=1.13.14
PKG_RELEASE:=21
PKG_RELEASE:=22
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)?
@@ -36,6 +36,7 @@ PKG_BUILD_FLAGS:=no-mips16
GO_PKG:=github.com/sagernet/sing-box
GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/sing-box
GO_PKG_LDFLAGS_X:=$(GO_PKG)/constant.Version=$(PKG_VERSION)
GO_PKG_LDFLAGS_X+=github.com/anytls/sing-anytls/util.Verison=mihomo/1.19.27
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk