-
Notifications
You must be signed in to change notification settings - Fork 91
/
Copy pathexecutable.lua
171 lines (147 loc) · 5.35 KB
/
executable.lua
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
local lazy = require("flutter-tools.lazy")
local utils = lazy.require("flutter-tools.utils") ---@module "flutter-tools.utils"
local path = lazy.require("flutter-tools.utils.path") ---@module "flutter-tools.utils.path"
local ui = lazy.require("flutter-tools.ui") ---@module "flutter-tools.ui"
local config = lazy.require("flutter-tools.config") ---@module "flutter-tools.config"
local Job = require("plenary.job")
local fn = vim.fn
local luv = vim.loop
local M = {}
local dart_sdk = path.join("cache", "dart-sdk")
local function _flutter_sdk_root(bin_path)
-- convert path/to/flutter/bin/flutter into path/to/flutter
return fn.fnamemodify(bin_path, ":h:h")
end
local function _dart_sdk_root(paths)
if paths.flutter_sdk then
-- On Linux installations with snap the dart SDK can be further nested inside a bin directory
-- so it's /bin/cache/dart-sdk whereas else where it is /cache/dart-sdk
local segments = { paths.flutter_sdk, "cache" }
if not path.is_dir(path.join(unpack(segments))) then table.insert(segments, 2, "bin") end
if path.is_dir(path.join(unpack(segments))) then
-- remove the /cache/ directory as it's already part of the SDK path above
segments[#segments] = nil
return path.join(unpack(vim.tbl_flatten({ segments, dart_sdk })))
end
end
if utils.executable("flutter") then
local flutter_path = fn.resolve(fn.exepath("flutter"))
local flutter_bin = fn.fnamemodify(flutter_path, ":h")
return path.join(flutter_bin, dart_sdk)
end
if utils.executable("dart") then return fn.resolve(fn.exepath("dart")) end
return ""
end
local function _flutter_sdk_dart_bin(flutter_sdk)
-- retrieve the Dart binary from the Flutter SDK
local binary_name = path.is_windows and "dart.bat" or "dart"
local dart_search_paths = {
path.join(flutter_sdk, "bin", binary_name),
path.join(flutter_sdk, "bin", "cache", "dart-sdk", "bin", binary_name)
}
for _, _path in ipairs(dart_search_paths) do
if path.exists(_path) then
return _path
end
end
return ""
end
---Get paths for flutter and dart based on the binary locations
---@return table<string, string>
local function get_default_binaries()
local flutter_bin = fn.resolve(fn.exepath("flutter"))
return {
flutter_bin = flutter_bin,
dart_bin = fn.resolve(fn.exepath("dart")),
flutter_sdk = _flutter_sdk_root(flutter_bin),
}
end
---@type table<string, string>
local _paths = nil
function M.reset_paths() _paths = nil end
---Execute user's lookup command and pass it to the job callback
---@param lookup_cmd string
---@param callback fun(p: string, t: table<string, string>?)
---@return table<string, string>?
local function path_from_lookup_cmd(lookup_cmd, callback)
local paths = {}
local parts = vim.split(lookup_cmd, " ")
local cmd = parts[1]
local args = vim.list_slice(parts, 2, #parts)
local job = Job:new({ command = cmd, args = args })
job:after_failure(
vim.schedule_wrap(
function()
ui.notify(string.format("Error running %s", lookup_cmd), ui.ERROR, { timeout = 5000 })
end
)
)
job:after_success(vim.schedule_wrap(function(j, _)
local result = j:result()
local flutter_sdk_path = result[1]
if flutter_sdk_path then
paths.dart_bin = _flutter_sdk_dart_bin(flutter_sdk_path)
paths.flutter_bin = path.join(flutter_sdk_path, "bin", "flutter")
paths.flutter_sdk = flutter_sdk_path
callback(paths)
else
paths = get_default_binaries()
callback(paths)
end
return paths
end))
job:start()
end
---Fetch the paths to the users binaries.
---@param callback fun(paths: table<string, string>)
---@return nil
function M.get(callback)
if _paths then return callback(_paths) end
if config.fvm then
local flutter_bin_symlink = path.join(luv.cwd(), ".fvm", "flutter_sdk", "bin", "flutter")
local flutter_bin = luv.fs_realpath(flutter_bin_symlink)
if path.exists(flutter_bin_symlink) and path.exists(flutter_bin) then
_paths = {
flutter_bin = flutter_bin,
flutter_sdk = _flutter_sdk_root(flutter_bin),
fvm = true,
}
_paths.dart_sdk = _dart_sdk_root(_paths)
_paths.dart_bin = _flutter_sdk_dart_bin(_paths.flutter_sdk)
return callback(_paths)
end
end
if config.flutter_path then
local flutter_path = fn.resolve(config.flutter_path)
_paths = { flutter_bin = flutter_path, flutter_sdk = _flutter_sdk_root(flutter_path) }
_paths.dart_sdk = _dart_sdk_root(_paths)
_paths.dart_bin = _flutter_sdk_dart_bin(_paths.flutter_sdk)
return callback(_paths)
end
if config.flutter_lookup_cmd then
return path_from_lookup_cmd(config.flutter_lookup_cmd, function(paths)
_paths = paths
_paths.dart_sdk = _dart_sdk_root(_paths)
callback(_paths)
end)
end
if not _paths then
_paths = get_default_binaries()
_paths.dart_sdk = _dart_sdk_root(_paths)
if _paths.flutter_sdk then _paths.dart_bin = _flutter_sdk_dart_bin(_paths.flutter_sdk) end
end
return callback(_paths)
end
---Fetch the path to the users flutter installation.
---@param callback fun(paths: string)
---@return nil
function M.flutter(callback)
M.get(function(paths) callback(paths.flutter_bin) end)
end
---Fetch the path to the users dart installation.
---@param callback fun(paths: table<string, string>)
---@return nil
function M.dart(callback)
M.get(function(paths) callback(paths.dart_bin) end)
end
return M