-
Notifications
You must be signed in to change notification settings - Fork 115
Expand file tree
/
Copy pathexecutable.lua
More file actions
229 lines (198 loc) · 7.22 KB
/
Copy pathexecutable.lua
File metadata and controls
229 lines (198 loc) · 7.22 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
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")
---@class flutter.Paths
---
--- The path to the Flutter CLI.
---@field flutter_bin string
---
--- The path to the root directory of the Flutter SDK.
---@field flutter_sdk string
---
--- The path to the Dart CLI.
---@field dart_bin string
---
--- The path to the root directory of the Dart SDK used by the Flutter SDK.
---@field dart_sdk string
---
--- True if fvm provides the Flutter SDK, otherwise nil or false.
---@field fvm boolean?
---@field emulator_bin string
---@private
---@class flutter.internal.Paths
---@field flutter_bin string
---@field flutter_sdk string
---@field dart_bin string
local fn = vim.fn
local fs = vim.fs
local luv = vim.loop
local M = {}
local dart_sdk = path.join("cache", "dart-sdk")
---@type flutter.Paths?
local cached_paths = nil
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(utils.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"
return path.join(flutter_sdk, "bin", binary_name)
end
--- Get paths for flutter and dart based on the binary locations.
---@return flutter.internal.Paths?
local function get_default_binaries()
local flutter_bin = fn.resolve(fn.exepath("flutter"))
if #flutter_bin <= 0 then return nil end
return {
flutter_bin = flutter_bin,
dart_bin = fn.resolve(fn.exepath("dart")),
flutter_sdk = flutter_sdk_root(flutter_bin),
emulator_bin = fn.resolve(fn.exepath("emulator")),
}
end
--- Execute user's lookup command and pass it to the job callback.
---@param lookup_cmd string
---@param callback fun(paths:flutter.internal.Paths):nil
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
end))
job:start()
end
local function flutter_bin_from_fvm()
local fvm_root =
fs.dirname(fs.find(".fvm", { path = luv.cwd(), upward = true, type = "directory" })[1])
local binary_name = path.is_windows and "flutter.bat" or "flutter"
local flutter_bin_symlink = path.join(fvm_root, ".fvm", "flutter_sdk", "bin", binary_name)
flutter_bin_symlink = fn.exepath(flutter_bin_symlink)
local flutter_bin = luv.fs_realpath(flutter_bin_symlink)
if path.exists(flutter_bin_symlink) and path.exists(flutter_bin) then return flutter_bin end
end
--- Reset the internally cached SDK paths.
function M.reset_paths() cached_paths = nil end
--- Fetch the paths to the users binaries.
---@param callback fun(paths: flutter.Paths):nil
function M.get(callback)
if cached_paths then return callback(cached_paths) end
if config.fvm then
local flutter_bin = flutter_bin_from_fvm()
if flutter_bin then
cached_paths = {
flutter_bin = flutter_bin,
flutter_sdk = flutter_sdk_root(flutter_bin),
fvm = true,
-- Provide default values to make the linter happy.
dart_sdk = "",
dart_bin = "",
emulator_bin = fn.exepath("emulator") or "",
}
cached_paths.dart_sdk = dart_sdk_root(cached_paths)
cached_paths.dart_bin = flutter_sdk_dart_bin(cached_paths.flutter_sdk)
return callback(cached_paths)
end
end
if config.flutter_path then
local flutter_path = fn.resolve(config.flutter_path)
cached_paths = {
flutter_bin = flutter_path,
flutter_sdk = flutter_sdk_root(flutter_path),
-- Provide default values to make the linter happy.
dart_sdk = "",
dart_bin = "",
emulator_bin = fn.exepath("emulator") or "",
}
cached_paths.dart_sdk = dart_sdk_root(cached_paths)
cached_paths.dart_bin = flutter_sdk_dart_bin(cached_paths.flutter_sdk)
return callback(cached_paths)
end
if config.flutter_lookup_cmd then
return path_from_lookup_cmd(config.flutter_lookup_cmd, function(paths)
paths = {
flutter_bin = paths.flutter_bin,
flutter_sdk = paths.flutter_sdk,
dart_bin = paths.dart_bin,
dart_sdk = dart_sdk_root(paths),
emulator_bin = fn.exepath("emulator") or "",
}
callback(paths)
end)
end
if not cached_paths then
local internal_paths = get_default_binaries()
if internal_paths then
cached_paths = {
flutter_bin = internal_paths.flutter_bin,
flutter_sdk = internal_paths.flutter_sdk,
dart_bin = internal_paths.dart_bin,
dart_sdk = dart_sdk_root(internal_paths),
emulator_bin = fn.exepath("emulator") or "",
}
if cached_paths.flutter_sdk then
cached_paths.dart_bin = flutter_sdk_dart_bin(cached_paths.flutter_sdk)
end
end
end
return callback(cached_paths)
end
--- Fetch the path to the users flutter installation.
---@param callback fun(flutter_bin: string):nil
function M.flutter(callback)
M.get(function(paths) callback(paths.flutter_bin) end)
end
--- Fetch the path to the users androidSdk -> emulator installation.
---@param callback fun(emulator_bin: string):nil
function M.emulator(callback)
M.get(function(paths) callback(paths.emulator_bin) end)
end
--- Fetch the path to the users dart installation.
---@param callback fun(dart_bin: string):nil
function M.dart(callback)
M.get(function(paths) callback(paths.dart_bin) end)
end
return M