diff --git a/lua/crates/api.lua b/lua/crates/api.lua index 9d4d1284..be737cfc 100644 --- a/lua/crates/api.lua +++ b/lua/crates/api.lua @@ -156,17 +156,17 @@ function M.parse_crate(json_str) for n, m in pairs(v.features) do table.sort(m) - table.insert(version.features, { + version.features:insert({ name = n, members = m, }) end - for _, f in ipairs(version.features) do + for _, f in ipairs(version.features.list) do for _, m in ipairs(f.members) do if not version.features:get_feat(m) then - table.insert(version.features, { + version.features:insert({ name = m, members = {}, }) @@ -178,15 +178,11 @@ function M.parse_crate(json_str) version.features:sort() - if not version.features[1] or not (version.features[1].name == "default") then - for i = #version.features, 1, -1 do - version.features[i + 1] = version.features[i] - end - - version.features[1] = { + if not version.features.list[1] or not (version.features.list[1].name == "default") then + version.features:insert({ name = "default", members = {}, - } + }) end table.insert(crate.versions, version) diff --git a/lua/crates/core.lua b/lua/crates/core.lua index f8ee234b..c5dd7615 100644 --- a/lua/crates/core.lua +++ b/lua/crates/core.lua @@ -28,7 +28,7 @@ M.reload_deps = async.wrap(function(crate_name, versions, version) for _, d in ipairs(deps) do if d.opt and not version.features:get_feat(d.name) then - table.insert(version.features, { + version.features:insert({ name = d.name, members = {}, }) diff --git a/lua/crates/diagnostic.lua b/lua/crates/diagnostic.lua index 9f9cb497..3a92b610 100644 --- a/lua/crates/diagnostic.lua +++ b/lua/crates/diagnostic.lua @@ -331,7 +331,7 @@ function M.process_crate_deps(crate, version, deps) local diagnostics = {} local valid_feats = {} - for _, f in ipairs(version.features) do + for _, f in ipairs(version.features.list) do table.insert(valid_feats, f.name) end for _, d in ipairs(deps) do diff --git a/lua/crates/popup/features.lua b/lua/crates/popup/features.lua index cf301b9e..7f6ccc17 100644 --- a/lua/crates/popup/features.lua +++ b/lua/crates/popup/features.lua @@ -59,7 +59,7 @@ local function toggle_feature(ctx, line) selected_feature = features:get_feat(m) end else - selected_feature = features[index] + selected_feature = features.list[index] end if not selected_feature then return end @@ -128,7 +128,7 @@ local function toggle_feature(ctx, line) table.insert(features_text, hi_text) end else - for _, f in ipairs(features) do + for _, f in ipairs(features.list) do local hi_text = feature_text(features_info, f) table.insert(features_text, hi_text) end @@ -150,7 +150,7 @@ local function goto_feature(ctx, line) selected_feature = version.features:get_feat(m) end else - selected_feature = version.features[index] + selected_feature = version.features.list[index] end if not selected_feature then return end @@ -292,7 +292,7 @@ function M.open_features(ctx, crate, version, opts) local features_text = {} local features_info = util.features_info(crate, features) - for _, f in ipairs(features) do + for _, f in ipairs(features.list) do local hl_text = feature_text(features_info, f) table.insert(features_text, hl_text) local w = 0 @@ -303,7 +303,7 @@ function M.open_features(ctx, crate, version, opts) end local width = popup.win_width(title, feat_width) - local height = popup.win_height(features) + local height = popup.win_height(features.list) if opts.update then popup.update_win(width, height, title, features_text, opts) diff --git a/lua/crates/src/common.lua b/lua/crates/src/common.lua index 21c56d72..c2fdd463 100644 --- a/lua/crates/src/common.lua +++ b/lua/crates/src/common.lua @@ -84,7 +84,7 @@ local function complete_features(crate, cf, versions) end local items = {} - for _, f in ipairs(newest.features) do + for _, f in ipairs(newest.features.list) do local crate_feat = crate:get_feat(f.name) if not crate_feat then local r = { diff --git a/lua/crates/types.lua b/lua/crates/types.lua index a9d38588..db51d8f6 100644 --- a/lua/crates/types.lua +++ b/lua/crates/types.lua @@ -131,6 +131,7 @@ local M = {CrateInfo = {}, Diagnostic = {}, Crate = {}, Version = {}, Features = + local Diagnostic = M.Diagnostic @@ -151,22 +152,20 @@ function Diagnostic:contains(line, col) end -function Features.new(obj) - return setmetatable(obj, { __index = Features }) +function Features.new(list) + local map = {} + for _, f in ipairs(list) do + map[f.name] = f + end + return setmetatable({ list = list, map = map }, { __index = Features }) end function Features:get_feat(name) - for i, f in ipairs(self) do - if f.name == name then - return f, i - end - end - - return nil, nil + return self.map[name] end function Features:sort() - table.sort(self, function(a, b) + table.sort(self.list, function(a, b) if a.name == "default" then return true elseif b.name == "default" then @@ -177,6 +176,11 @@ function Features:sort() end) end +function Features:insert(feat) + table.insert(self.list, feat) + self.map[feat.name] = feat +end + function SemVer.new(obj) return setmetatable(obj, { __index = SemVer }) diff --git a/lua/crates/util.lua b/lua/crates/util.lua index 062f9289..3a1ba7e4 100644 --- a/lua/crates/util.lua +++ b/lua/crates/util.lua @@ -125,7 +125,7 @@ function M.features_info(crate, features) end end - for _, f in ipairs(features) do + for _, f in ipairs(features.list) do local enabled = M.is_feat_enabled(crate, f) local i = info[f.name] if i then diff --git a/teal/crates/api.tl b/teal/crates/api.tl index c8753c35..540acb25 100644 --- a/teal/crates/api.tl +++ b/teal/crates/api.tl @@ -148,7 +148,7 @@ function M.parse_crate(json_str: string): Crate|nil if v.num then local version: Version = { num = v.num as string, - features = Features.new {}, + features = Features.new({}), yanked = v.yanked as boolean, parsed = semver.parse_version(v.num as string), created = DateTime.parse_rfc_3339(v.created_at as string) @@ -156,17 +156,17 @@ function M.parse_crate(json_str: string): Crate|nil for n,m in pairs(v.features as {string:{string}}) do table.sort(m) - table.insert(version.features, { + version.features:insert({ name = n, members = m, }) end -- add optional dependency members as features - for _,f in ipairs(version.features) do + for _,f in ipairs(version.features.list) do for _,m in ipairs(f.members) do if not version.features:get_feat(m) then - table.insert(version.features, { + version.features:insert({ name = m, members = {}, }) @@ -178,15 +178,11 @@ function M.parse_crate(json_str: string): Crate|nil version.features:sort() -- add missing default feature - if not version.features[1] or not (version.features[1].name == "default") then - for i=#version.features, 1, -1 do - version.features[i + 1] = version.features[i] - end - - version.features[1] = { + if not version.features.list[1] or not (version.features.list[1].name == "default") then + version.features:insert({ name = "default", members = {}, - } + }) end table.insert(crate.versions, version) diff --git a/teal/crates/core.tl b/teal/crates/core.tl index ad9670e3..0cb18fd1 100644 --- a/teal/crates/core.tl +++ b/teal/crates/core.tl @@ -28,7 +28,7 @@ M.reload_deps = async.wrap(function(crate_name: string, versions: {Version}, ver for _,d in ipairs(deps) do -- optional dependencies are automatically promoted to features if d.opt and not version.features:get_feat(d.name) then - table.insert(version.features, { + version.features:insert({ name = d.name, members = {}, }) diff --git a/teal/crates/diagnostic.tl b/teal/crates/diagnostic.tl index 711df8a8..8c537c5d 100644 --- a/teal/crates/diagnostic.tl +++ b/teal/crates/diagnostic.tl @@ -331,7 +331,7 @@ function M.process_crate_deps(crate: toml.Crate, version: Version, deps: {Depend local diagnostics = {} local valid_feats = {} - for _,f in ipairs(version.features) do + for _,f in ipairs(version.features.list) do table.insert(valid_feats, f.name) end for _,d in ipairs(deps) do diff --git a/teal/crates/popup/features.tl b/teal/crates/popup/features.tl index ddb33009..6fe5cbc6 100644 --- a/teal/crates/popup/features.tl +++ b/teal/crates/popup/features.tl @@ -59,7 +59,7 @@ local function toggle_feature(ctx: FeatureContext, line: integer) selected_feature = features:get_feat(m) end else - selected_feature = features[index] + selected_feature = features.list[index] end if not selected_feature then return end @@ -128,7 +128,7 @@ local function toggle_feature(ctx: FeatureContext, line: integer) table.insert(features_text, hi_text) end else - for _,f in ipairs(features) do + for _,f in ipairs(features.list) do local hi_text = feature_text(features_info, f) table.insert(features_text, hi_text) end @@ -150,7 +150,7 @@ local function goto_feature(ctx: FeatureContext, line: integer) selected_feature = version.features:get_feat(m) end else - selected_feature = version.features[index] + selected_feature = version.features.list[index] end if not selected_feature then return end @@ -292,7 +292,7 @@ function M.open_features(ctx: FeatureContext, crate: toml.Crate, version: Versio local features_text: {{HighlightText}} = {} local features_info = util.features_info(crate, features) - for _,f in ipairs(features) do + for _,f in ipairs(features.list) do local hl_text = feature_text(features_info, f) table.insert(features_text, hl_text) local w = 0 @@ -303,7 +303,7 @@ function M.open_features(ctx: FeatureContext, crate: toml.Crate, version: Versio end local width = popup.win_width(title, feat_width) - local height = popup.win_height(features) + local height = popup.win_height(features.list) if opts.update then popup.update_win(width, height, title, features_text, opts) diff --git a/teal/crates/src/common.tl b/teal/crates/src/common.tl index 7749d0c8..cc56e9e8 100644 --- a/teal/crates/src/common.tl +++ b/teal/crates/src/common.tl @@ -84,7 +84,7 @@ local function complete_features(crate: toml.Crate, cf: toml.Feature, versions: end local items = {} - for _,f in ipairs(newest.features) do + for _,f in ipairs(newest.features.list) do local crate_feat = crate:get_feat(f.name) if not crate_feat then local r: CompletionItem = { diff --git a/teal/crates/types.tl b/teal/crates/types.tl index bc8619cf..f07cf79f 100644 --- a/teal/crates/types.tl +++ b/teal/crates/types.tl @@ -74,7 +74,8 @@ local record M end record Features - {Feature} + list: {Feature} + map: {string:Feature} end record Feature @@ -151,22 +152,20 @@ function Diagnostic:contains(line: integer, col: integer): boolean end -function Features.new(obj: Features): Features - return setmetatable(obj, { __index = Features }) -end - -function Features:get_feat(name: string): Feature|nil, integer|nil - for i,f in ipairs(self) do - if f.name == name then - return f, i - end +function Features.new(list: {Feature}): Features + local map = {} + for _,f in ipairs(list) do + map[f.name] = f end + return setmetatable({ list = list, map = map }, { __index = Features }) +end - return nil, nil +function Features:get_feat(name: string): Feature|nil + return self.map[name] end function Features:sort() - table.sort(self, function (a: Feature, b: Feature): boolean + table.sort(self.list, function (a: Feature, b: Feature): boolean if a.name == "default" then return true elseif b.name == "default" then @@ -177,6 +176,11 @@ function Features:sort() end) end +function Features:insert(feat: Feature) + table.insert(self.list, feat) + self.map[feat.name] = feat +end + function SemVer.new(obj: SemVer): SemVer return setmetatable(obj, { __index = SemVer }) diff --git a/teal/crates/util.tl b/teal/crates/util.tl index 5a803db9..93344d39 100644 --- a/teal/crates/util.tl +++ b/teal/crates/util.tl @@ -125,7 +125,7 @@ function M.features_info(crate: toml.Crate, features: Features): {string:Feature end end - for _,f in ipairs(features) do + for _,f in ipairs(features.list) do local enabled = M.is_feat_enabled(crate, f) local i = info[f.name] if i then