-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathutil.tl
142 lines (116 loc) · 3.52 KB
/
util.tl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
local _module_name = "util"
local uv <const> = require("luv")
local tracing <const> = require("teal_language_server.tracing")
local record util
record TryOpts<T>
action:function():T
catch:function(err:any):T
finally:function()
end
enum PlatformType
"linux"
"osx"
"windows"
"unknown"
end
end
local _uname_info:uv.UnameInfo = nil
local _os_type:util.PlatformType = nil
local function _get_uname_info():uv.UnameInfo
if _uname_info == nil then
_uname_info = uv.os_uname()
assert(_uname_info ~= nil)
end
return _uname_info
end
local function _on_error(error_obj:string):any
return debug.traceback(error_obj, 2)
end
function util.string_escape_special_chars(value:string):string
-- gsub is not ideal in cases where we want to do a literal
-- replace, so to do this just escape all special characters with '%'
value = value:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0")
-- Note that we don't put this all in the return statement to avoid
-- forwarding the multiple return values causing subtle errors
return value
end
function util.string_starts_with(str:string, prefix:string):boolean
return str:sub(1, #prefix) == prefix
end
function util.string_split(str:string, delimiter:string):{string}
-- Unclear whether this should return {} or {''} so just fail instead
-- Most split functions do one of these two things so there isn't really a standard here
-- So force calling code to decide
assert(#str > 0, "Unclear how to split an empty string")
assert(delimiter ~= nil, "missing delimiter")
assert(delimiter is string)
assert(#delimiter > 0)
local num_delimiter_chars = #delimiter
delimiter = util.string_escape_special_chars(delimiter)
local start_index = 1
local result:{string} = {}
while true do
local delimiter_index, _ = str:find(delimiter, start_index)
if delimiter_index == nil then
table.insert(result, str:sub(start_index))
break
end
table.insert(result, str:sub(start_index, delimiter_index-1))
start_index = delimiter_index + num_delimiter_chars
end
return result
end
function util.string_join(delimiter:string, items:{string}):string
assert(delimiter is string)
assert(items ~= nil)
local result = ''
for _, item in ipairs(items) do
if #result ~= 0 then
result = result .. delimiter
end
result = result .. tostring(item)
end
return result
end
function util.get_platform():util.PlatformType
if _os_type == nil then
local raw_os_name = string.lower(_get_uname_info().sysname)
if raw_os_name == "linux" then
_os_type = "linux"
elseif raw_os_name:find("darwin") ~= nil then
_os_type = "osx"
elseif raw_os_name:find("windows") ~= nil or raw_os_name:find("mingw") ~= nil then
_os_type = "windows"
else
tracing.warning(_module_name, "Unrecognized platform {}", {raw_os_name})
_os_type = "unknown"
end
end
return _os_type
end
function util.try<T>(t:util.TryOpts<T>):T
local success, ret_value = xpcall(t.action, _on_error)
if success then
if t.finally then
t.finally()
end
return ret_value
end
if not t.catch then
if t.finally then
t.finally()
end
error(ret_value, 2)
end
success, ret_value = xpcall((function():T
return t.catch(ret_value)
end), _on_error) as (boolean, T)
if t.finally then
t.finally()
end
if success then
return ret_value
end
return error(ret_value, 2)
end
return util