From e2fcc41b4a2ff30a67d8a6aeb59133bdce79ebe1 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 15 May 2021 14:17:36 +0200 Subject: [PATCH 01/22] Ensure tabs don't extend beyond window's width --- data/core/rootview.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 5664c08f..4cf50b55 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -278,7 +278,8 @@ end function Node:get_tab_rect(idx) - local tw = math.min(style.tab_width, math.ceil(self.size.x / #self.views)) + local twp = math.floor((self.size.x - style.padding.x) / #self.views + 0.5) + local tw = math.min(style.tab_width, twp) local h = style.font:get_height() + style.padding.y * 2 return self.position.x + (idx-1) * tw, self.position.y, tw, h end From 50a4fc212fc96647dafa261401529fe1f7e27a82 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 15 May 2021 14:49:16 +0200 Subject: [PATCH 02/22] Do not truncate filenames in tab and use dots --- data/core/rootview.lua | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 4cf50b55..d0a1e825 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -397,6 +397,7 @@ end function Node:draw_tabs() local x, y, _, h = self:get_tab_rect(1) local ds = style.divider_size + local dots_width = style.font:get_width("...") core.push_clip_rect(x, y, self.size.x, h) renderer.draw_rect(x, y, self.size.x, h, style.background2) renderer.draw_rect(x, y + h - ds, self.size.x, ds, style.divider) @@ -423,9 +424,20 @@ function Node:draw_tabs() color = style.text end local padx = style.padding.x - core.push_clip_rect(x, y, show_close_button and cx - x - cspace or w - padx, h) + core.push_clip_rect(x, y, cx - x, h) + local text_avail_width = cx - x - padx x, w = x + padx, w - padx * 2 - local align = style.font:get_width(text) > w and "left" or "center" + local align = "center" + if style.font:get_width(text) > text_avail_width then + align = "left" + for i = 1, #text do + local reduced_text = text:sub(1, #text - i) + if style.font:get_width(reduced_text) + dots_width <= text_avail_width then + text = reduced_text .. "..." + break + end + end + end common.draw_text(style.font, color, text, align, x, y, w, h) core.pop_clip_rect() end From f30dfc20fead9ef4679df2517904b0b23445e63b Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 15 May 2021 16:26:15 +0200 Subject: [PATCH 03/22] More accurate tab width calculation Ensure the right side of the right-most tab always end up at the same position. --- data/core/rootview.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index d0a1e825..7dd5b9a0 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -278,10 +278,11 @@ end function Node:get_tab_rect(idx) - local twp = math.floor((self.size.x - style.padding.x) / #self.views + 0.5) - local tw = math.min(style.tab_width, twp) + local tw = math.min(style.tab_width, (self.size.x - style.padding.x) / #self.views) + local x_left = self.position.x + tw * (idx - 1) + local x1, x2 = math.floor(x_left), math.floor(x_left + tw) local h = style.font:get_height() + style.padding.y * 2 - return self.position.x + (idx-1) * tw, self.position.y, tw, h + return x1, self.position.y, x2 - x1, h end From b223dbca6f81c51f595c51560b6ee53f919c45f0 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 15 May 2021 16:27:29 +0200 Subject: [PATCH 04/22] Use unicode ellipsis to truncate tab's text For proportional fonts is equivalent to three dots but it makes a lot of difference for monospaced fonts. --- data/core/rootview.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 7dd5b9a0..c4e49c09 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -398,7 +398,7 @@ end function Node:draw_tabs() local x, y, _, h = self:get_tab_rect(1) local ds = style.divider_size - local dots_width = style.font:get_width("...") + local dots_width = style.font:get_width("…") core.push_clip_rect(x, y, self.size.x, h) renderer.draw_rect(x, y, self.size.x, h, style.background2) renderer.draw_rect(x, y + h - ds, self.size.x, ds, style.divider) @@ -425,8 +425,13 @@ function Node:draw_tabs() color = style.text end local padx = style.padding.x - core.push_clip_rect(x, y, cx - x, h) + -- Normally we should substract "cspace" from text_avail_width and from the + -- clipping width. It is the padding space we give to the left and right of the + -- close button. However, since we are using dots to terminate filenames, we + -- choose to ignore "cspace" accepting that the text can possibly "touch" the + -- close button. local text_avail_width = cx - x - padx + core.push_clip_rect(x, y, cx - x, h) x, w = x + padx, w - padx * 2 local align = "center" if style.font:get_width(text) > text_avail_width then @@ -434,7 +439,7 @@ function Node:draw_tabs() for i = 1, #text do local reduced_text = text:sub(1, #text - i) if style.font:get_width(reduced_text) + dots_width <= text_avail_width then - text = reduced_text .. "..." + text = reduced_text .. "…" break end end From 90e41daa99dca7a297fb27a226cf80c7f5dfc232 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 15 May 2021 16:57:20 +0200 Subject: [PATCH 05/22] Add tab animation and improve hovering update Always update the tab hovering status using the Node:update method. Previous behavior was to update only on mouse moved events. --- data/core/rootview.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index c4e49c09..da628c7e 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -57,7 +57,10 @@ function Node:new(type) if self.type == "leaf" then self:add_view(EmptyView()) end + self.hovered = {x = -1, y = -1 } self.hovered_close = 0 + self.tab_margin = style.padding.x + self.move_towards = View.move_towards end @@ -68,9 +71,8 @@ end function Node:on_mouse_moved(x, y, ...) - self.hovered_tab = self:get_tab_overlapping_point(x, y) if self.type == "leaf" then - self:tab_mouse_moved(x, y) + self.hovered.x, self.hovered.y = x, y self.active_view:on_mouse_moved(x, y, ...) else self:propagate("on_mouse_moved", x, y, ...) @@ -250,8 +252,9 @@ local function close_button_location(x, w) end -function Node:tab_mouse_moved(px, py) +function Node:tab_hovered_update(px, py) local tab_index = self:get_tab_overlapping_point(px, py) + self.hovered_tab = tab_index if tab_index then local x, y, w, h = self:get_tab_rect(tab_index) local cx, cw = close_button_location(x, w) @@ -278,7 +281,7 @@ end function Node:get_tab_rect(idx) - local tw = math.min(style.tab_width, (self.size.x - style.padding.x) / #self.views) + local tw = math.min(style.tab_width, (self.size.x - self.tab_margin) / #self.views) local x_left = self.position.x + tw * (idx - 1) local x1, x2 = math.floor(x_left), math.floor(x_left + tw) local h = style.font:get_height() + style.padding.y * 2 @@ -388,6 +391,8 @@ function Node:update() for _, view in ipairs(self.views) do view:update() end + self:tab_hovered_update(self.hovered.x, self.hovered.y) + self:move_towards("tab_margin", style.padding.x) else self.a:update() self.b:update() @@ -635,6 +640,8 @@ function RootView:on_mouse_pressed(button, x, y, clicks) local idx = node:get_tab_overlapping_point(x, y) if idx then if button == "middle" or node.hovered_close == idx then + local _, _, tw = node:get_tab_rect(idx) + node.tab_margin = node.tab_margin + tw node:close_view(self.root_node, node.views[idx]) else self.dragged_node = idx From b37c190db22489c7978012550cbb5f884d5e62bf Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sun, 16 May 2021 15:50:27 +0200 Subject: [PATCH 06/22] Add buttons to scroll tabs when there are too many Use config.max_tabs to configure the maximum number of tabs that can be shown. Beyond the maximum value scroll buttons will appear to scroll the tabs. --- data/core/config.lua | 1 + data/core/rootview.lua | 136 ++++++++++++++++++++++++--- data/fonts/icons.ttf | Bin 9620 -> 10036 bytes dev-utils/fontello-config-small.json | 118 ----------------------- 4 files changed, 122 insertions(+), 133 deletions(-) delete mode 100644 dev-utils/fontello-config-small.json diff --git a/data/core/config.lua b/data/core/config.lua index f9b4e87f..74ca3d2f 100644 --- a/data/core/config.lua +++ b/data/core/config.lua @@ -11,6 +11,7 @@ config.symbol_pattern = "[%a_][%w_]*" config.non_word_chars = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-" config.undo_merge_timeout = 0.3 config.max_undos = 10000 +config.max_tabs = 10 config.highlight_current_line = true config.line_height = 1.2 config.indent_size = 2 diff --git a/data/core/rootview.lua b/data/core/rootview.lua index da628c7e..1ed571a4 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -1,5 +1,6 @@ local core = require "core" local common = require "core.common" +local config = require "core.config" local style = require "core.style" local keymap = require "core.keymap" local Object = require "core.object" @@ -59,7 +60,9 @@ function Node:new(type) end self.hovered = {x = -1, y = -1 } self.hovered_close = 0 - self.tab_margin = style.padding.x + self.tab_shift = 0 + self.tab_offset = 1 + self.tab_width = style.tab_width self.move_towards = View.move_towards end @@ -236,11 +239,20 @@ function Node:get_divider_overlapping_point(px, py) end +function Node:get_visible_tabs_number() + return math.min(#self.views - self.tab_offset + 1, config.max_tabs) +end + + function Node:get_tab_overlapping_point(px, py) if #self.views == 1 then return nil end - local x, y, w, h = self:get_tab_rect(1) - if px >= x and py >= y and px < x + w * #self.views and py < y + h then - return math.floor((px - x) / w) + 1 + local tabs_number = self:get_visible_tabs_number() + -- FIXME: looping over tabs is may be not needed. Find a simpler way. + for i = self.tab_offset, self.tab_offset + tabs_number - 1 do + local x, y, w, h = self:get_tab_rect(i) + if px >= x and py >= y and px < x + w and py < y + h then + return i + end end end @@ -252,18 +264,33 @@ local function close_button_location(x, w) end +function Node:get_scroll_button_index(px, py) + for i = 1, 2 do + local x, y, w, h = self:get_scroll_button_rect(i) + if px >= x and px < x + w and py >= y and py < y + h then + return i + end + end +end + + function Node:tab_hovered_update(px, py) local tab_index = self:get_tab_overlapping_point(px, py) self.hovered_tab = tab_index + self.hovered_close = 0 + self.hovered_tab_scroll = 0 if tab_index then local x, y, w, h = self:get_tab_rect(tab_index) local cx, cw = close_button_location(x, w) if px >= cx and px < cx + cw and py >= y and py < y + h then self.hovered_close = tab_index - return + end + else + local tab_scroll_index = self:get_scroll_button_index(px, py) + if tab_scroll_index then + self.hovered_tab_scroll = tab_scroll_index end end - self.hovered_close = 0 end @@ -280,10 +307,24 @@ function Node:get_child_overlapping_point(x, y) end +function Node:get_scroll_button_rect(index) + local w = style.icon_font:get_width(">") + local pad = w + local h = style.font:get_height() + style.padding.y * 2 + if index == 1 then + return self.position.x, self.position.y, w + 2 * pad, h, pad + else + return self.position.x + self.size.x - w - 2 * pad, self.position.y, w + 2 * pad, h, pad + end +end + + function Node:get_tab_rect(idx) - local tw = math.min(style.tab_width, (self.size.x - self.tab_margin) / #self.views) - local x_left = self.position.x + tw * (idx - 1) - local x1, x2 = math.floor(x_left), math.floor(x_left + tw) + -- FIXME: we may consider to create a separate method just to get the + -- width of the scroll button. It is needed to compute tabs placement. + local _, _, sbw = self:get_scroll_button_rect(1) + local x_left = self.position.x + sbw + self.tab_width * (idx - 1) - self.tab_shift + local x1, x2 = math.floor(x_left), math.floor(x_left + self.tab_width) local h = style.font:get_height() + style.padding.y * 2 return x1, self.position.y, x2 - x1, h end @@ -386,13 +427,61 @@ function Node:update_layout() end +function Node:scroll_tabs_to_visible() + local index = self:get_view_idx(self.active_view) + if index then + local tabs_number = self:get_visible_tabs_number() + if self.tab_offset > index then + self.tab_offset = index + elseif self.tab_offset + tabs_number - 1 < index then + self.tab_offset = index - tabs_number + 1 + elseif tabs_number < config.max_tabs and self.tab_offset > 1 then + self.tab_offset = #self.views - config.max_tabs + 1 + end + end +end + + +function Node:scroll_tabs(dir) + local view_index = self:get_view_idx(self.active_view) + if dir == 1 then + if self.tab_offset > 1 then + self.tab_offset = self.tab_offset - 1 + local last_index = self.tab_offset + self:get_visible_tabs_number() - 1 + if view_index > last_index then + self:set_active_view(self.views[last_index]) + end + end + elseif dir == 2 then + local tabs_number = self:get_visible_tabs_number() + if self.tab_offset + tabs_number - 1 < #self.views then + self.tab_offset = self.tab_offset + 1 + local view_index = self:get_view_idx(self.active_view) + if view_index < self.tab_offset then + self:set_active_view(self.views[self.tab_offset]) + end + end + end +end + + +function Node:target_tab_width() + local tabs_number = self:get_visible_tabs_number() + local _, _, sbw = self:get_scroll_button_rect(1) + return math.min(style.tab_width, (self.size.x - sbw * 2) / tabs_number) +end + + function Node:update() if self.type == "leaf" then + self:scroll_tabs_to_visible() for _, view in ipairs(self.views) do view:update() end self:tab_hovered_update(self.hovered.x, self.hovered.y) - self:move_towards("tab_margin", style.padding.x) + local tab_width = self:target_tab_width() + self:move_towards("tab_shift", tab_width * (self.tab_offset - 1)) + self:move_towards("tab_width", tab_width) else self.a:update() self.b:update() @@ -401,14 +490,27 @@ end function Node:draw_tabs() - local x, y, _, h = self:get_tab_rect(1) + local x, y, w, h, scroll_padding = self:get_scroll_button_rect(1) local ds = style.divider_size local dots_width = style.font:get_width("…") core.push_clip_rect(x, y, self.size.x, h) renderer.draw_rect(x, y, self.size.x, h, style.background2) renderer.draw_rect(x, y + h - ds, self.size.x, ds, style.divider) - for i, view in ipairs(self.views) do + if self.tab_offset > 1 then + local button_style = self.hovered_tab_scroll == 1 and style.text or style.dim + common.draw_text(style.icon_font, button_style, "<", nil, x + scroll_padding, y, 0, h) + end + + local tabs_number = self:get_visible_tabs_number() + if #self.views > self.tab_offset + tabs_number - 1 then + local xrb, yrb, wrb = self:get_scroll_button_rect(2) + local button_style = self.hovered_tab_scroll == 2 and style.text or style.dim + common.draw_text(style.icon_font, button_style, ">", nil, xrb + scroll_padding, yrb, 0, h) + end + + for i = self.tab_offset, self.tab_offset + tabs_number - 1 do + local view = self.views[i] local x, y, w, h = self:get_tab_rect(i) local text = view:get_name() local color = style.dim @@ -637,11 +739,13 @@ function RootView:on_mouse_pressed(button, x, y, clicks) return end local node = self.root_node:get_child_overlapping_point(x, y) + if node.hovered_tab_scroll > 0 then + node:scroll_tabs(node.hovered_tab_scroll) + return + end local idx = node:get_tab_overlapping_point(x, y) if idx then if button == "middle" or node.hovered_close == idx then - local _, _, tw = node:get_tab_rect(idx) - node.tab_margin = node.tab_margin + tw node:close_view(self.root_node, node.views[idx]) else self.dragged_node = idx @@ -702,7 +806,9 @@ function RootView:on_mouse_moved(x, y, dx, dy) local node = self.root_node:get_child_overlapping_point(x, y) local div = self.root_node:get_divider_overlapping_point(x, y) local tab_index = node and node:get_tab_overlapping_point(x, y) - if div then + if node and node:get_scroll_button_index(x, y) then + system.set_cursor("arrow") + elseif div then local axis = (div.type == "hsplit" and "x" or "y") if div.a:is_resizable(axis) and div.b:is_resizable(axis) then system.set_cursor(div.type == "hsplit" and "sizeh" or "sizev") diff --git a/data/fonts/icons.ttf b/data/fonts/icons.ttf index 00b4cc3bd262b1cb9f3339d2e5379c4b45f983c2..43ab376735b7a7a4355a91dacd639d4dcc8d285e 100644 GIT binary patch delta 1138 zcmb`G-%C?r7{{OYoU_fHGq<^&ZIaW?A8qp&O$ogjCgz2uiIn++8nWqr7@Hn+s8P5m zx(iW`7hZ(cMN&d2Orh>V=*H_n3F)eESQkMEMz!_4XGiD{XfNOQ`##V6>^YzJJ==2k zcJE?UI`jvC^Z~%YXfh=EUv&F0ehI)FkItmr23NirptK+N8=_Jy8E*P@590>_Mnfz# zEn(h_aSwV?EO9rg+q32XxMke`7LSC+%FC9509LGrmN+JKyX;qt-(Xx5Pp0O&20!G# zVB!!H{fWuZ(D_7d7(n!6+>i{-Nu=EP7USC(yC*`)$c}OP2gdgi@Rc+_0R|bXp^(V z#ZuQYO|qZiTtum%b#&B#M;Sh#qYmoi>x@@t1rd8{Wx`g=YfM>y0}b}n>WXltA3Z)& z05IUP*r;T{M9mB(7O)l)>MUZDd3li$VgY^oRLBQ6R8dg8SVhI?Lj_$03O}NXo?uKB{tO_hssufz%7Q+w zik@>;m6(Zgn&O6AwAt&#eGBV0xr!I(*(U`-CK@-Qzc5OvXBDu z7^`TiT@ToRMl-|1!`luAqbse~Gj`ELv{hc>x!6itnq9;$G7GtVQp@wfwBQtSVL>3P zd<7rmnT^~*ZeLmQWDT9H3PO;tz>WpblnScEe`)DmBzfEH$~+Mj~cX*SG`m;xtYVzbB&hws-vow@9@v^s1w z&t~%{B!d5>hp0U&dBSqVTSw-Z0p=NV%673EoW%Xs_%$n)!+mDQY0V^xaxc~qF delta 718 zcmX|8OK4L;6g~64wMp~ZJZ;1T6VsRqwxAX2!a${U;U`Mb(h4r>OPY_+*hdqz;-b)% zxU!BQO2r^uR8X@>UAS>!K?G4;NH@B0BSz^$)M7v|-bn@-&O7g%xpVKGxvQscowyO5 zPjv!p6u@}8;JCYQC$^AY0hH(IOQnc6+!z45S82a5>*fln{eP~K{sj2EIj887Pv^TI z5x3>0uVgDPhduyW9_U!gXPl|f+UrArU!(oOJQ?N-^(*NF=~%u{nj4uo-1tn!c`}mI zGifJ09<7rW3HKD7IhO@}&q%)~9l7WfGEaTQpQL|LgAd)AV(Gxn)8Bw?Woo+Joz1w} z;mQ)_-dL=kW7qi@%k{5=(P7{n)aG9waXW>tL&GxpA-aJIFLq%s`uPS6b4%G5WaPJ2 z1kvV-L9969Jf-wfDuZ{aJ-n&}`F+J0)O4d+1u)wHdP6D!kGJJ@2=c+|L|4m@Uq7W- z;AO?MT7k9y{sXmlewdVic)Sq_o%o1^D43KmiBC#UeTabyP$M`aAv&6n@DQJs5Va>I zM5j|N3{b~FR>C6ANzlY`K|);UvV^~SQ>(D*qWRksx;u1lWztG)!cv>J`gmvU4TV84 zU$zfgw(!+jW0PfQmJ9rceXQpRt1F{QSyj|m+L(4t`>yZMkLqRpuQ6-9Z4S?_rnY`j Vn9Yv|;=B}y@yCI3HMza!`v*8uh9>|3 diff --git a/dev-utils/fontello-config-small.json b/dev-utils/fontello-config-small.json deleted file mode 100644 index 895de303..00000000 --- a/dev-utils/fontello-config-small.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "name": "icons", - "css_prefix_text": "icon-", - "css_use_suffix": false, - "hinting": true, - "units_per_em": 1000, - "ascent": 850, - "glyphs": [ - { - "uid": "9dd9e835aebe1060ba7190ad2b2ed951", - "css": "search-1", - "code": 76, - "src": "fontawesome" - }, - { - "uid": "c76b7947c957c9b78b11741173c8349b", - "css": "attention-1", - "code": 33, - "src": "fontawesome" - }, - { - "uid": "1b5a5d7b7e3c71437f5a26befdd045ed", - "css": "doc-1", - "code": 102, - "src": "fontawesome" - }, - { - "uid": "f8aa663c489bcbd6e68ec8147dca841e", - "css": "folder-1", - "code": 100, - "src": "fontawesome" - }, - { - "uid": "c95735c17a10af81448c7fed98a04546", - "css": "folder-open-1", - "code": 68, - "src": "fontawesome" - }, - { - "uid": "e99461abfef3923546da8d745372c995", - "css": "cog", - "code": 80, - "src": "fontawesome" - }, - { - "uid": "7bf14281af5633a597f85b061ef1cfb9", - "css": "angle-right", - "code": 43, - "src": "fontawesome" - }, - { - "uid": "e4dde1992f787163e2e2b534b8c8067d", - "css": "angle-down", - "code": 45, - "src": "fontawesome" - }, - { - "uid": "ea2d9a8c51ca42b38ef0d2a07f16d9a7", - "css": "chart-line", - "code": 103, - "src": "fontawesome" - }, - { - "uid": "f4445feb55521283572ee88bc304f928", - "css": "floppy", - "code": 83, - "src": "fontawesome" - }, - { - "uid": "9755f76110ae4d12ac5f9466c9152031", - "css": "book", - "code": 66, - "src": "fontawesome" - }, - { - "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", - "css": "info-circled-1", - "code": 105, - "src": "fontawesome" - }, - { - "uid": "5211af474d3a9848f67f945e2ccaf143", - "css": "cancel-1", - "code": 67, - "src": "fontawesome" - }, - { - "uid": "04f022b8bd044d4ccfffd3887ff72088", - "css": "window-minimize", - "code": 95, - "src": "fontawesome" - }, - { - "uid": "d0e62145dbf40f30e47b3819b8b43a8f", - "css": "window-restore", - "code": 119, - "src": "fontawesome" - }, - { - "uid": "7394501fc0b17cb7bda99538f92e26d6", - "css": "window-close", - "code": 88, - "src": "fontawesome" - }, - { - "uid": "559647a6f430b3aeadbecd67194451dd", - "css": "menu-1", - "code": 77, - "src": "fontawesome" - }, - { - "uid": "07f0832c07f3d9713fffb06c8bffa027", - "css": "window-maximize", - "code": 87, - "src": "fontawesome" - } - ] -} \ No newline at end of file From 9c9fbe4c8b93b3eeadc63ccce9971a15d70598d5 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sun, 16 May 2021 10:11:12 -0700 Subject: [PATCH 07/22] Add macos minimum OS variable in info.plist --- dev-utils/Info.plist | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-utils/Info.plist b/dev-utils/Info.plist index 76c7efda..75591560 100644 --- a/dev-utils/Info.plist +++ b/dev-utils/Info.plist @@ -14,6 +14,7 @@ APPL NSHighResolutionCapable + MinimumOSVersion10.13 CFBundleShortVersionString 1.16.5 NSHumanReadableCopyright From c7b1a6f53e75218bb9956004680a6cdbea137a59 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 16 May 2021 13:23:17 -0400 Subject: [PATCH 08/22] Allowed for optional boolean to better match filenames. (#180) --- data/core/common.lua | 16 ++++++------ src/api/system.c | 59 ++++++++++++++++++++++++++++++++------------ 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/data/core/common.lua b/data/core/common.lua index 5f6e8bc9..05f91111 100644 --- a/data/core/common.lua +++ b/data/core/common.lua @@ -58,10 +58,10 @@ local function compare_score(a, b) return a.score > b.score end -local function fuzzy_match_items(items, needle) +local function fuzzy_match_items(items, needle, files) local res = {} for _, item in ipairs(items) do - local score = system.fuzzy_match(tostring(item), needle) + local score = system.fuzzy_match(tostring(item), needle, files) if score then table.insert(res, { text = item, score = score }) end @@ -74,11 +74,11 @@ local function fuzzy_match_items(items, needle) end -function common.fuzzy_match(haystack, needle) +function common.fuzzy_match(haystack, needle, files) if type(haystack) == "table" then - return fuzzy_match_items(haystack, needle) + return fuzzy_match_items(haystack, needle, files) end - return system.fuzzy_match(haystack, needle) + return system.fuzzy_match(haystack, needle, files) end @@ -86,16 +86,16 @@ function common.fuzzy_match_with_recents(haystack, recents, needle) if needle == "" then local recents_ext = {} for i = 2, #recents do - table.insert(recents_ext, recents[i]) + table.insert(recents_ext, recents[i]) end table.insert(recents_ext, recents[1]) - local others = common.fuzzy_match(haystack, "") + local others = common.fuzzy_match(haystack, "", true) for i = 1, #others do table.insert(recents_ext, others[i]) end return recents_ext else - return fuzzy_match_items(haystack, needle) + return fuzzy_match_items(haystack, needle, true) end end diff --git a/src/api/system.c b/src/api/system.c index 1b15a2ec..89c037c2 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -517,27 +517,54 @@ static int f_exec(lua_State *L) { static int f_fuzzy_match(lua_State *L) { - const char *str = luaL_checkstring(L, 1); - const char *ptn = luaL_checkstring(L, 2); + size_t strLen, ptnLen; + const char *str = luaL_checklstring(L, 1, &strLen); + const char *ptn = luaL_checklstring(L, 2, &ptnLen); + bool files = false; + if (lua_gettop(L) > 2 && lua_isboolean(L,3)) + files = lua_toboolean(L, 3); + int score = 0; int run = 0; - - while (*str && *ptn) { - while (*str == ' ') { str++; } - while (*ptn == ' ') { ptn++; } - if (tolower(*str) == tolower(*ptn)) { - score += run * 10 - (*str != *ptn); - run++; - ptn++; - } else { - score -= 10; - run = 0; + + // Match things *backwards*. This allows for better matching on filenames than the above + // function. For example, in the lite project, opening "renderer" has lib/font_render/build.sh + // as the first result, rather than src/renderer.c. Clearly that's wrong. + if (files) { + const char* strEnd = str + strLen - 1; + const char* ptnEnd = ptn + ptnLen - 1; + while (strEnd >= str && ptnEnd >= ptn) { + while (*strEnd == ' ') { strEnd--; } + while (*ptnEnd == ' ') { ptnEnd--; } + if (tolower(*strEnd) == tolower(*ptnEnd)) { + score += run * 10 - (*strEnd != *ptnEnd); + run++; + ptnEnd--; + } else { + score -= 10; + run = 0; + } + strEnd--; } - str++; + if (ptnEnd >= ptn) { return 0; } + } else { + while (*str && *ptn) { + while (*str == ' ') { str++; } + while (*ptn == ' ') { ptn++; } + if (tolower(*str) == tolower(*ptn)) { + score += run * 10 - (*str != *ptn); + run++; + ptn++; + } else { + score -= 10; + run = 0; + } + str++; + } + if (*ptn) { return 0; } } - if (*ptn) { return 0; } - lua_pushnumber(L, score - (int) strlen(str)); + lua_pushnumber(L, score - (int)strLen); return 1; } From bd4efa14a2ef5518ab7109977041375843544ab8 Mon Sep 17 00:00:00 2001 From: Cukmekerb Date: Sun, 16 May 2021 23:56:21 -0700 Subject: [PATCH 09/22] add `of` keyword to language_js.lua and improve js string syntax highlighting in (#186) --- data/plugins/language_js.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/plugins/language_js.lua b/data/plugins/language_js.lua index a258bb3c..671e1bd8 100644 --- a/data/plugins/language_js.lua +++ b/data/plugins/language_js.lua @@ -7,7 +7,7 @@ syntax.add { patterns = { { pattern = "//.-\n", type = "comment" }, { pattern = { "/%*", "%*/" }, type = "comment" }, - { pattern = { '/', '/', '\\' }, type = "string" }, + { pattern = { '/%g', '/', '\\' }, type = "string" }, { pattern = { '"', '"', '\\' }, type = "string" }, { pattern = { "'", "'", '\\' }, type = "string" }, { pattern = { "`", "`", '\\' }, type = "string" }, @@ -41,6 +41,7 @@ syntax.add { ["if"] = "keyword", ["import"] = "keyword", ["in"] = "keyword", + ["of"] = "keyword", ["instanceof"] = "keyword", ["let"] = "keyword", ["new"] = "keyword", From e54ffc49eaf65c57e840bddcdef7e5d7f62e49f8 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 May 2021 03:14:46 -0400 Subject: [PATCH 10/22] Added in keyboard shortcuts to the project search module. (#188) --- data/plugins/projectsearch.lua | 36 +++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/data/plugins/projectsearch.lua b/data/plugins/projectsearch.lua index 4c1fca6d..ef887b41 100644 --- a/data/plugins/projectsearch.lua +++ b/data/plugins/projectsearch.lua @@ -265,12 +265,38 @@ command.add(ResultsView, { ["project-search:refresh"] = function() core.active_view:refresh() end, + + ["project-search:move-to-previous-page"] = function() + local view = core.active_view + view.scroll.to.y = view.scroll.to.y - view.size.y + end, + + ["project-search:move-to-next-page"] = function() + local view = core.active_view + view.scroll.to.y = view.scroll.to.y + view.size.y + end, + + ["project-search:move-to-start-of-doc"] = function() + local view = core.active_view + view.scroll.to.y = 0 + end, + + ["project-search:move-to-end-of-doc"] = function() + local view = core.active_view + view.scroll.to.y = view:get_scrollable_size() + end }) keymap.add { - ["f5"] = "project-search:refresh", - ["ctrl+shift+f"] = "project-search:find", - ["up"] = "project-search:select-previous", - ["down"] = "project-search:select-next", - ["return"] = "project-search:open-selected", + ["f5"] = "project-search:refresh", + ["ctrl+shift+f"] = "project-search:find", + ["up"] = "project-search:select-previous", + ["down"] = "project-search:select-next", + ["return"] = "project-search:open-selected", + ["pageup"] = "project-search:move-to-previous-page", + ["pagedown"] = "project-search:move-to-next-page", + ["ctrl+home"] = "project-search:move-to-start-of-doc", + ["ctrl+end"] = "project-search:move-to-end-of-doc", + ["home"] = "project-search:move-to-start-of-doc", + ["end"] = "project-search:move-to-end-of-doc" } From 85d0d684dec52095f1c73f9914754ad042e81da6 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 May 2021 03:16:20 -0400 Subject: [PATCH 11/22] Truncated lines longer than 256 characters, and skipped to the relevant portion of the line to reduce slowdown and increase relevancy. (#185) --- data/plugins/projectsearch.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/plugins/projectsearch.lua b/data/plugins/projectsearch.lua index ef887b41..ed818bf6 100644 --- a/data/plugins/projectsearch.lua +++ b/data/plugins/projectsearch.lua @@ -30,7 +30,10 @@ local function find_all_matches_in_file(t, filename, fn) for line in fp:lines() do local s = fn(line) if s then - table.insert(t, { file = filename, text = line, line = n, col = s }) + -- Insert maximum 256 characters. If we insert more, for compiled files, which can have very long lines + -- things tend to get sluggish. If our line is longer than 80 characters, begin to truncate the thing. + local start_index = math.max(s - 80, 1) + table.insert(t, { file = filename, text = (start_index > 1 and "..." or "") .. line:sub(start_index, 256 + start_index), line = n, col = s }) core.redraw = true end if n % 100 == 0 then coroutine.yield() end From e43f1b9df9644791cdd3c7649810b556855c1f66 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 May 2021 03:29:51 -0400 Subject: [PATCH 12/22] Unified open and saving style. (#189) --- data/core/commands/core.lua | 3 ++- data/core/commands/doc.lua | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/data/core/commands/core.lua b/data/core/commands/core.lua index c8233062..abbe7cb4 100644 --- a/data/core/commands/core.lua +++ b/data/core/commands/core.lua @@ -88,7 +88,8 @@ command.add(nil, { ["core:open-file"] = function() local view = core.active_view if view.doc and view.doc.abs_filename then - core.command_view:set_text(common.home_encode(view.doc.abs_filename)) + local dirname, filename = view.doc.abs_filename:match("(.*)[/\\](.+)$") + core.command_view:set_text(core.normalize_to_project_dir(dirname) .. PATHSEP) end core.command_view:enter("Open File", function(text) core.root_view:open_doc(core.open_doc(common.home_expand(text))) diff --git a/data/core/commands/doc.lua b/data/core/commands/doc.lua index 965f3451..ee930150 100644 --- a/data/core/commands/doc.lua +++ b/data/core/commands/doc.lua @@ -299,6 +299,9 @@ local commands = { ["doc:save-as"] = function() if doc().filename then core.command_view:set_text(doc().filename) + elseif core.last_active_view then + local dirname, filename = core.last_active_view.doc.abs_filename:match("(.*)[/\\](.+)$") + core.command_view:set_text(core.normalize_to_project_dir(dirname) .. PATHSEP) end core.command_view:enter("Save As", function(filename) save(common.home_expand(filename)) From 6e08c3321c2770f6ecada953b9bb610fd64c58a9 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 May 2021 04:05:08 -0400 Subject: [PATCH 13/22] Fixed a bug where if detectindent is paired with another plugin that hooks the event, it'll overwrite the other plugin's functions. (#190) --- data/plugins/detectindent.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/data/plugins/detectindent.lua b/data/plugins/detectindent.lua index 681dce26..079a92e7 100644 --- a/data/plugins/detectindent.lua +++ b/data/plugins/detectindent.lua @@ -102,21 +102,28 @@ end local doc_on_text_change = Doc.on_text_change local adjust_threshold = 4 +local current_on_text_change = nil + local function update_cache(doc) local type, size, score = detect_indent_stat(doc) cache[doc] = { type = type, size = size, confirmed = (score >= adjust_threshold) } doc.indent_info = cache[doc] if score < adjust_threshold and doc_on_text_change then - Doc.on_text_change = function(self, ...) - doc_on_text_change(self, ...) + current_on_text_change = function(self, ...) update_cache(self) end elseif score >= adjust_threshold and doc_on_text_change then - Doc.on_text_change = doc_on_text_change - doc_on_text_change = nil + current_on_text_change = nil end end +function Doc:on_text_change(...) + if current_on_text_change then + current_on_text_change(...) + end + doc_on_text_change(...) +end + local new = Doc.new function Doc:new(...) From 92322986b8e938a9d76c5420600db9e867871dec Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 17 May 2021 10:16:55 +0200 Subject: [PATCH 14/22] Fix error with previous commit Error was introduced with PR: https://github.com/franko/lite-xl/pull/190 --- data/plugins/detectindent.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/plugins/detectindent.lua b/data/plugins/detectindent.lua index 079a92e7..63fe8a52 100644 --- a/data/plugins/detectindent.lua +++ b/data/plugins/detectindent.lua @@ -117,7 +117,7 @@ local function update_cache(doc) end end -function Doc:on_text_change(...) +function Doc.on_text_change(...) if current_on_text_change then current_on_text_change(...) end From ba40bc0dfc8fe02e47de5cb81ed1be6ecafc0973 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 17 May 2021 12:14:01 +0200 Subject: [PATCH 15/22] Final adjustments to tab's rect computations --- data/core/rootview.lua | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 1ed571a4..981734f8 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -224,6 +224,15 @@ function Node:get_children(t) end +-- return the width including the padding space and separately +-- the padding space itself +local function get_scroll_button_width() + local w = style.icon_font:get_width(">") + local pad = w + return w + 2 * pad, pad +end + + function Node:get_divider_overlapping_point(px, py) if self.type ~= "leaf" then local p = 6 @@ -247,12 +256,10 @@ end function Node:get_tab_overlapping_point(px, py) if #self.views == 1 then return nil end local tabs_number = self:get_visible_tabs_number() - -- FIXME: looping over tabs is may be not needed. Find a simpler way. - for i = self.tab_offset, self.tab_offset + tabs_number - 1 do - local x, y, w, h = self:get_tab_rect(i) - if px >= x and py >= y and px < x + w and py < y + h then - return i - end + local x1, y1, w, h = self:get_tab_rect(self.tab_offset) + local x2, y2 = self:get_tab_rect(self.tab_offset + tabs_number) + if px >= x1 and py >= y1 and px < x2 and py < y1 + h then + return math.floor((px - x1) / w) + self.tab_offset end end @@ -308,25 +315,18 @@ end function Node:get_scroll_button_rect(index) - local w = style.icon_font:get_width(">") - local pad = w + local w, pad = get_scroll_button_width() local h = style.font:get_height() + style.padding.y * 2 - if index == 1 then - return self.position.x, self.position.y, w + 2 * pad, h, pad - else - return self.position.x + self.size.x - w - 2 * pad, self.position.y, w + 2 * pad, h, pad - end + local x = self.position.x + (index == 1 and 0 or self.size.x - w) + return x, self.position.y, w, h, pad end function Node:get_tab_rect(idx) - -- FIXME: we may consider to create a separate method just to get the - -- width of the scroll button. It is needed to compute tabs placement. - local _, _, sbw = self:get_scroll_button_rect(1) - local x_left = self.position.x + sbw + self.tab_width * (idx - 1) - self.tab_shift - local x1, x2 = math.floor(x_left), math.floor(x_left + self.tab_width) + local sbw = get_scroll_button_width() + local x = self.position.x + sbw + self.tab_width * (idx - 1) - self.tab_shift local h = style.font:get_height() + style.padding.y * 2 - return x1, self.position.y, x2 - x1, h + return x, self.position.y, self.tab_width, h end @@ -467,7 +467,7 @@ end function Node:target_tab_width() local tabs_number = self:get_visible_tabs_number() - local _, _, sbw = self:get_scroll_button_rect(1) + local sbw = get_scroll_button_width() return math.min(style.tab_width, (self.size.x - sbw * 2) / tabs_number) end From 13529c28d4a3a16e94053de524d26b9b5ca6cc00 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 17 May 2021 13:37:05 +0200 Subject: [PATCH 16/22] Cosmetic variable name change --- data/core/rootview.lua | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 981734f8..3f300b45 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -285,7 +285,7 @@ function Node:tab_hovered_update(px, py) local tab_index = self:get_tab_overlapping_point(px, py) self.hovered_tab = tab_index self.hovered_close = 0 - self.hovered_tab_scroll = 0 + self.hovered_scroll_button = 0 if tab_index then local x, y, w, h = self:get_tab_rect(tab_index) local cx, cw = close_button_location(x, w) @@ -293,10 +293,7 @@ function Node:tab_hovered_update(px, py) self.hovered_close = tab_index end else - local tab_scroll_index = self:get_scroll_button_index(px, py) - if tab_scroll_index then - self.hovered_tab_scroll = tab_scroll_index - end + self.hovered_scroll_button = self:get_scroll_button_index(px, py) or 0 end end @@ -498,14 +495,14 @@ function Node:draw_tabs() renderer.draw_rect(x, y + h - ds, self.size.x, ds, style.divider) if self.tab_offset > 1 then - local button_style = self.hovered_tab_scroll == 1 and style.text or style.dim + local button_style = self.hovered_scroll_button == 1 and style.text or style.dim common.draw_text(style.icon_font, button_style, "<", nil, x + scroll_padding, y, 0, h) end local tabs_number = self:get_visible_tabs_number() if #self.views > self.tab_offset + tabs_number - 1 then local xrb, yrb, wrb = self:get_scroll_button_rect(2) - local button_style = self.hovered_tab_scroll == 2 and style.text or style.dim + local button_style = self.hovered_scroll_button == 2 and style.text or style.dim common.draw_text(style.icon_font, button_style, ">", nil, xrb + scroll_padding, yrb, 0, h) end @@ -739,8 +736,8 @@ function RootView:on_mouse_pressed(button, x, y, clicks) return end local node = self.root_node:get_child_overlapping_point(x, y) - if node.hovered_tab_scroll > 0 then - node:scroll_tabs(node.hovered_tab_scroll) + if node.hovered_scroll_button > 0 then + node:scroll_tabs(node.hovered_scroll_button) return end local idx = node:get_tab_overlapping_point(x, y) From 1fb01f36df1adb9b2e2ae0c39de3757b65a63f57 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 17 May 2021 15:11:06 +0200 Subject: [PATCH 17/22] Avoid overflowing tab rectangles when animating --- data/core/rootview.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 3f300b45..17bb7c77 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -321,9 +321,12 @@ end function Node:get_tab_rect(idx) local sbw = get_scroll_button_width() - local x = self.position.x + sbw + self.tab_width * (idx - 1) - self.tab_shift + local maxw = self.size.x - 2 * sbw + local x0 = self.position.x + sbw + local x1 = x0 + common.clamp(self.tab_width * (idx - 1) - self.tab_shift, 0, maxw) + local x2 = x0 + common.clamp(self.tab_width * idx - self.tab_shift, 0, maxw) local h = style.font:get_height() + style.padding.y * 2 - return x, self.position.y, self.tab_width, h + return x1, self.position.y, x2 - x1, h end From ca05562cc0d7160780663d7f3d0008b3c9c2ceb0 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 17 May 2021 15:16:57 +0200 Subject: [PATCH 18/22] Restore correct fontello configuration --- dev-utils/fontello-config.json | 378 +++------------------------------ 1 file changed, 30 insertions(+), 348 deletions(-) diff --git a/dev-utils/fontello-config.json b/dev-utils/fontello-config.json index 9dd4681d..42334c2f 100644 --- a/dev-utils/fontello-config.json +++ b/dev-utils/fontello-config.json @@ -1,5 +1,5 @@ { - "name": "", + "name": "icons", "css_prefix_text": "icon-", "css_use_suffix": false, "hinting": true, @@ -12,234 +12,18 @@ "code": 76, "src": "fontawesome" }, - { - "uid": "12f4ece88e46abd864e40b35e05b11cd", - "css": "ok-1", - "code": 59402, - "src": "fontawesome" - }, - { - "uid": "43ab845088317bd348dee1d975700c48", - "css": "ok-circled-1", - "code": 59403, - "src": "fontawesome" - }, - { - "uid": "ad33e708f4d2e25c5056c931da1528d6", - "css": "ok-circled2", - "code": 59405, - "src": "fontawesome" - }, - { - "uid": "1400d5103edd2fa6d2d61688fee79a5a", - "css": "ok-squared", - "code": 61770, - "src": "fontawesome" - }, - { - "uid": "5211af474d3a9848f67f945e2ccaf143", - "css": "cancel-1", - "code": 67, - "src": "fontawesome" - }, - { - "uid": "0f4cae16f34ae243a6144c18a003f2d8", - "css": "cancel-circled-1", - "code": 99, - "src": "fontawesome" - }, - { - "uid": "d7271d490b71df4311e32cdacae8b331", - "css": "home-1", - "code": 59407, - "src": "fontawesome" - }, - { - "uid": "3d4ea8a78dc34efe891f3a0f3d961274", - "css": "info", - "code": 61737, - "src": "fontawesome" - }, - { - "uid": "ce3cf091d6ebd004dd0b52d24074e6e3", - "css": "help", - "code": 61736, - "src": "fontawesome" - }, - { - "uid": "17ebadd1e3f274ff0205601eef7b9cc4", - "css": "help-circled-1", - "code": 59408, - "src": "fontawesome" - }, - { - "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", - "css": "info-circled-1", - "code": 59409, - "src": "fontawesome" - }, - { - "uid": "c1f1975c885aa9f3dad7810c53b82074", - "css": "lock", - "code": 59410, - "src": "fontawesome" - }, - { - "uid": "657ab647f6248a6b57a5b893beaf35a9", - "css": "lock-open-1", - "code": 59411, - "src": "fontawesome" - }, - { - "uid": "05376be04a27d5a46e855a233d6e8508", - "css": "lock-open-alt-1", - "code": 61758, - "src": "fontawesome" - }, - { - "uid": "3db5347bd219f3bce6025780f5d9ef45", - "css": "tag", - "code": 59412, - "src": "fontawesome" - }, - { - "uid": "a3f89e106175a5c5c4e9738870b12e55", - "css": "tags", - "code": 59413, - "src": "fontawesome" - }, - { - "uid": "7034e4d22866af82bef811f52fb1ba46", - "css": "code", - "code": 61729, - "src": "fontawesome" - }, - { - "uid": "d35a1d35efeb784d1dc9ac18b9b6c2b6", - "css": "pencil-1", - "code": 59414, - "src": "fontawesome" - }, - { - "uid": "44fae3bfdd54754dc68ec50d37efea37", - "css": "pencil-squared", - "code": 61771, - "src": "fontawesome" - }, - { - "uid": "41087bc74d4b20b55059c60a33bf4008", - "css": "edit", - "code": 59415, - "src": "fontawesome" - }, - { - "uid": "ecb97add13804c190456025e43ec003b", - "css": "keyboard", - "code": 61724, - "src": "fontawesome" - }, { "uid": "c76b7947c957c9b78b11741173c8349b", "css": "attention-1", "code": 33, "src": "fontawesome" }, - { - "uid": "00391fac5d419345ffcccd95b6f76263", - "css": "attention-alt-1", - "code": 61738, - "src": "fontawesome" - }, - { - "uid": "b035c28eba2b35c6ffe92aee8b0df507", - "css": "attention-circled", - "code": 59417, - "src": "fontawesome" - }, - { - "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", - "css": "trash-empty", - "code": 59418, - "src": "fontawesome" - }, { "uid": "1b5a5d7b7e3c71437f5a26befdd045ed", "css": "doc-1", "code": 102, "src": "fontawesome" }, - { - "uid": "c8585e1e5b0467f28b70bce765d5840c", - "css": "docs", - "code": 61637, - "src": "fontawesome" - }, - { - "uid": "5408be43f7c42bccee419c6be53fdef5", - "css": "doc-text", - "code": 61686, - "src": "fontawesome" - }, - { - "uid": "178053298e3e5b03551d754d4b9acd8b", - "css": "doc-inv", - "code": 61787, - "src": "fontawesome" - }, - { - "uid": "c08a1cde48d96cba21d8c05fa7d7feb1", - "css": "doc-text-inv", - "code": 61788, - "src": "fontawesome" - }, - { - "uid": "9daa1fdf0838118518a7e22715e83abc", - "css": "file-pdf", - "code": 61889, - "src": "fontawesome" - }, - { - "uid": "310ffd629da85142bc8669f010556f2d", - "css": "file-word", - "code": 61890, - "src": "fontawesome" - }, - { - "uid": "edcd4022de8d8df266ef7c42d2658ca5", - "css": "file-powerpoint", - "code": 61892, - "src": "fontawesome" - }, - { - "uid": "3c961c1a8d874815856fc6637dc5a13c", - "css": "file-image", - "code": 61893, - "src": "fontawesome" - }, - { - "uid": "e80ae555c1413a4ec18b33fb348b4049", - "css": "file-archive", - "code": 61894, - "src": "fontawesome" - }, - { - "uid": "81db033e704eb7c586a365559d7c0f36", - "css": "file-audio", - "code": 61895, - "src": "fontawesome" - }, - { - "uid": "dd69d9aa589ea7bc0a82a3fe67039f4b", - "css": "file-video", - "code": 61896, - "src": "fontawesome" - }, - { - "uid": "26613a2e6bc41593c54bead46f8c8ee3", - "css": "file-code", - "code": 61897, - "src": "fontawesome" - }, { "uid": "f8aa663c489bcbd6e68ec8147dca841e", "css": "folder-1", @@ -252,58 +36,10 @@ "code": 68, "src": "fontawesome" }, - { - "uid": "b091a8bd0fdade174951f17d936f51e4", - "css": "folder-empty-1", - "code": 61716, - "src": "fontawesome" - }, - { - "uid": "6533bdc16ab201eb3f3b27ce989cab33", - "css": "folder-open-empty-1", - "code": 61717, - "src": "fontawesome" - }, - { - "uid": "559647a6f430b3aeadbecd67194451dd", - "css": "menu-1", - "code": 61641, - "src": "fontawesome" - }, { "uid": "e99461abfef3923546da8d745372c995", "css": "cog", - "code": 59422, - "src": "fontawesome" - }, - { - "uid": "98687378abd1faf8f6af97c254eb6cd6", - "css": "cog-alt", - "code": 59423, - "src": "fontawesome" - }, - { - "uid": "5bb103cd29de77e0e06a52638527b575", - "css": "wrench", - "code": 59424, - "src": "fontawesome" - }, - { - "uid": "0b2b66e526028a6972d51a6f10281b4b", - "css": "zoom-in", - "code": 59425, - "src": "fontawesome" - }, - { - "uid": "d25d10efa900f529ad1d275657cfd30e", - "css": "zoom-out", - "code": 59426, - "src": "fontawesome" - }, - { - "uid": "f3f90c8c89795da30f7444634476ea4f", - "css": "angle-left", - "code": 61700, + "code": 80, "src": "fontawesome" }, { @@ -312,24 +48,12 @@ "code": 43, "src": "fontawesome" }, - { - "uid": "5de9370846a26947e03f63142a3f1c07", - "css": "angle-up", - "code": 61701, - "src": "fontawesome" - }, { "uid": "e4dde1992f787163e2e2b534b8c8067d", "css": "angle-down", "code": 45, "src": "fontawesome" }, - { - "uid": "bbfb51903f40597f0b70fd75bc7b5cac", - "css": "trash", - "code": 61944, - "src": "fontawesome" - }, { "uid": "ea2d9a8c51ca42b38ef0d2a07f16d9a7", "css": "chart-line", @@ -342,106 +66,64 @@ "code": 83, "src": "fontawesome" }, - { - "uid": "b429436ec5a518c78479d44ef18dbd60", - "css": "paste", - "code": 61674, - "src": "fontawesome" - }, - { - "uid": "8772331a9fec983cdb5d72902a6f9e0e", - "css": "scissors", - "code": 59428, - "src": "fontawesome" - }, { "uid": "9755f76110ae4d12ac5f9466c9152031", "css": "book", - "code": 59429, + "code": 66, "src": "fontawesome" }, { - "uid": "f9cbf7508cd04145ade2800169959eef", - "css": "font", - "code": 59430, + "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", + "css": "info-circled-1", + "code": 105, "src": "fontawesome" }, { - "uid": "d3b3f17bc3eb7cd809a07bbd4d178bee", - "css": "resize-vertical", - "code": 59431, + "uid": "5211af474d3a9848f67f945e2ccaf143", + "css": "cancel-1", + "code": 67, "src": "fontawesome" }, { - "uid": "3c73d058e4589b65a8d959c0fc8f153d", - "css": "resize-horizontal", - "code": 59432, + "uid": "04f022b8bd044d4ccfffd3887ff72088", + "css": "window-minimize", + "code": 95, "src": "fontawesome" }, { - "uid": "e594fc6e5870b4ab7e49f52571d52577", - "css": "resize-full", - "code": 59433, + "uid": "d0e62145dbf40f30e47b3819b8b43a8f", + "css": "window-restore", + "code": 119, "src": "fontawesome" }, { - "uid": "5278ef7773e948d56c4d442c8c8c98cf", - "css": "lightbulb", - "code": 61675, + "uid": "7394501fc0b17cb7bda99538f92e26d6", + "css": "window-close", + "code": 88, "src": "fontawesome" }, { - "uid": "598a5f2bcf3521d1615de8e1881ccd17", - "css": "clock", - "code": 59434, + "uid": "559647a6f430b3aeadbecd67194451dd", + "css": "menu-1", + "code": 77, "src": "fontawesome" }, { - "uid": "1c4068ed75209e21af36017df8871802", - "css": "down-big", - "code": 59435, + "uid": "07f0832c07f3d9713fffb06c8bffa027", + "css": "window-maximize", + "code": 87, "src": "fontawesome" }, { - "uid": "555ef8c86832e686fef85f7af2eb7cde", - "css": "left-big", - "code": 59436, + "uid": "d870630ff8f81e6de3958ecaeac532f2", + "css": "left-open", + "code": 60, "src": "fontawesome" }, { - "uid": "ad6b3fbb5324abe71a9c0b6609cbb9f1", - "css": "right-big", - "code": 59437, - "src": "fontawesome" - }, - { - "uid": "95376bf082bfec6ce06ea1cda7bd7ead", - "css": "up-big", - "code": 59438, - "src": "fontawesome" - }, - { - "uid": "107ce08c7231097c7447d8f4d059b55f", - "css": "ellipsis", - "code": 61761, - "src": "fontawesome" - }, - { - "uid": "750058837a91edae64b03d60fc7e81a7", - "css": "ellipsis-vert", - "code": 61762, - "src": "fontawesome" - }, - { - "uid": "8fb55fd696d9a0f58f3b27c1d8633750", - "css": "table", - "code": 61646, - "src": "fontawesome" - }, - { - "uid": "53dd31a6cc6438192b2d7b09b1c1dd45", - "css": "columns", - "code": 61659, + "uid": "399ef63b1e23ab1b761dfbb5591fa4da", + "css": "right-open", + "code": 62, "src": "fontawesome" } ] From ba4fbde33db9b8061effa8f8b2882887ae1800af Mon Sep 17 00:00:00 2001 From: lqdev Date: Tue, 18 May 2021 17:52:18 +0200 Subject: [PATCH 19/22] fixed mixed indentation --- data/core/tokenizer.lua | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/data/core/tokenizer.lua b/data/core/tokenizer.lua index f3070995..a4fe2867 100644 --- a/data/core/tokenizer.lua +++ b/data/core/tokenizer.lua @@ -38,23 +38,23 @@ local function find_non_escaped(text, pattern, offset, esc) end end --- State is a 32-bit number that is four separate bytes, illustrating how many --- differnet delimiters we have open, and which subsyntaxes we have active. --- At most, there are 3 subsyntaxes active at the same time. Beyond that, +-- State is a 32-bit number that is four separate bytes, illustrating how many +-- differnet delimiters we have open, and which subsyntaxes we have active. +-- At most, there are 3 subsyntaxes active at the same time. Beyond that, -- does not support further highlighting. local function retrieve_syntax_state(incoming_syntax, state) - local current_syntax, subsyntax_info, current_state, current_level = + local current_syntax, subsyntax_info, current_state, current_level = incoming_syntax, nil, state, 0 if state > 0 and (state > 255 or current_syntax.patterns[state].syntax) then - -- If we have higher bits, then decode them one at a time, and find which - -- syntax we're using. Rather than walking the bytes, and calling into + -- If we have higher bits, then decode them one at a time, and find which + -- syntax we're using. Rather than walking the bytes, and calling into -- `syntax` each time, we could probably cache this in a single table. for i=0,2 do local target = bit32.extract(state, i*8, 8) if target ~= 0 then if current_syntax.patterns[target].syntax then subsyntax_info = current_syntax.patterns[target] - current_syntax = type(subsyntax_info.syntax) == "table" and + current_syntax = type(subsyntax_info.syntax) == "table" and subsyntax_info.syntax or syntax.get(subsyntax_info.syntax) current_state = 0 current_level = i+1 @@ -62,7 +62,7 @@ local function retrieve_syntax_state(incoming_syntax, state) current_state = target break end - else + else break end end @@ -77,28 +77,28 @@ function tokenizer.tokenize(incoming_syntax, text, state) if #incoming_syntax.patterns == 0 then return { "normal", text } end - + state = state or 0 - local current_syntax, subsyntax_info, current_state, current_level = + local current_syntax, subsyntax_info, current_state, current_level = retrieve_syntax_state(incoming_syntax, state) while i <= #text do -- continue trying to match the end pattern of a pair if we have a state set if current_state > 0 then local p = current_syntax.patterns[current_state] local s, e = find_non_escaped(text, p.pattern[2], i, p.pattern[3]) - + local cont = true -- If we're in subsyntax mode, always check to see if we end our syntax -- first. if subsyntax_info then local ss, se = find_non_escaped( - text, - subsyntax_info.pattern[2], - i, - subsyntax_info.pattern[3] - ) + text, + subsyntax_info.pattern[2], + i, + subsyntax_info.pattern[3] + ) if ss and (s == nil or ss < s) then - push_token(res, p.type, text:sub(i, ss - 1)) + push_token(res, p.type, text:sub(i, ss - 1)) i = ss cont = false end @@ -118,17 +118,17 @@ function tokenizer.tokenize(incoming_syntax, text, state) -- Check for end of syntax. if subsyntax_info then local s, e = find_non_escaped( - text, - "^" .. subsyntax_info.pattern[2], - i, - nil + text, + "^" .. subsyntax_info.pattern[2], + i, + nil ) if s then push_token(res, subsyntax_info.type, text:sub(i, e)) current_level = current_level - 1 -- Zero out the state above us, as well as our new current state. state = bit32.replace(state, 0, current_level*8, 16) - current_syntax, subsyntax_info, current_state, current_level = + current_syntax, subsyntax_info, current_state, current_level = retrieve_syntax_state(incoming_syntax, state) i = e + 1 end @@ -143,20 +143,20 @@ function tokenizer.tokenize(incoming_syntax, text, state) if s then -- matched pattern; make and add token local t = text:sub(s, e) - + push_token(res, current_syntax.symbols[t] or p.type, t) -- update state if this was a start|end pattern pair if type(p.pattern) == "table" then state = bit32.replace(state, n, current_level*8, 8) - -- If we've found a new subsyntax, bump our level, and set the - -- appropriate variables. + -- If we've found a new subsyntax, bump our level, and set the + -- appropriate variables. if p.syntax then current_level = current_level + 1 subsyntax_info = p - current_syntax = type(p.syntax) == "table" and - p.syntax or syntax.get(p.syntax) + current_syntax = type(p.syntax) == "table" and + p.syntax or syntax.get(p.syntax) current_state = 0 - else + else current_state = n end end From a92d15fe300f589041965f063c1a062ca86309bb Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Wed, 19 May 2021 10:09:40 +0200 Subject: [PATCH 20/22] Use all the available space for tabs Use a tab's width larger than style.tab_width if there is enough available space to display the number of tabs specified in config.max_tabs. --- data/core/rootview.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/core/rootview.lua b/data/core/rootview.lua index 17bb7c77..7cdc78cb 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -466,9 +466,9 @@ end function Node:target_tab_width() - local tabs_number = self:get_visible_tabs_number() - local sbw = get_scroll_button_width() - return math.min(style.tab_width, (self.size.x - sbw * 2) / tabs_number) + local n = self:get_visible_tabs_number() + local w = self.size.x - get_scroll_button_width() * 2 + return common.clamp(style.tab_width, w / config.max_tabs, w / n) end From 86a7037ed9c6abfa014e1e12a6212f7c3afa63c6 Mon Sep 17 00:00:00 2001 From: liquidev Date: Wed, 19 May 2021 22:35:28 +0200 Subject: [PATCH 21/22] support for multiple groups in one pattern (#196) --- data/core/tokenizer.lua | 47 +++++++++++++++++++++++++++++++------ data/plugins/language_c.lua | 28 +++++++++++----------- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/data/core/tokenizer.lua b/data/core/tokenizer.lua index a4fe2867..6d51928c 100644 --- a/data/core/tokenizer.lua +++ b/data/core/tokenizer.lua @@ -15,6 +15,39 @@ local function push_token(t, type, text) end +local function push_tokens(t, syn, pattern, full_text, find_results) + if #find_results > 2 then + -- We do some manipulation with find_results so that it's arranged + -- like this: + -- { start, end, i_1, i_2, i_3, …, i_last } + -- Each position spans characters from i_n to ((i_n+1) - 1), to form + -- consecutive spans of text. + -- + -- If i_1 is not equal to start, start is automatically inserted at + -- that index. + if find_results[3] ~= find_results[1] then + table.insert(find_results, 3, find_results[1]) + end + -- Copy the ending index to the end of the table, so that an ending index + -- always follows a starting index after position 3 in the table. + table.insert(find_results, find_results[2] + 1) + -- Then, we just iterate over our modified table. + for i = 3, #find_results - 1 do + local start = find_results[i] + local fin = find_results[i + 1] - 1 + local type = pattern.type[i - 2] + -- ↑ (i - 2) to convert from [3; n] to [1; n] + local text = full_text:sub(start, fin) + push_token(t, syn.symbols[text] or type, text) + end + else + local start, fin = find_results[1], find_results[2] + local text = full_text:sub(start, fin) + push_token(t, syn.symbols[text] or pattern.type, text) + end +end + + local function is_escaped(text, idx, esc) local byte = esc:byte() local count = 0 @@ -49,7 +82,7 @@ local function retrieve_syntax_state(incoming_syntax, state) -- If we have higher bits, then decode them one at a time, and find which -- syntax we're using. Rather than walking the bytes, and calling into -- `syntax` each time, we could probably cache this in a single table. - for i=0,2 do + for i = 0, 2 do local target = bit32.extract(state, i*8, 8) if target ~= 0 then if current_syntax.patterns[target].syntax then @@ -138,13 +171,13 @@ function tokenizer.tokenize(incoming_syntax, text, state) local matched = false for n, p in ipairs(current_syntax.patterns) do local pattern = (type(p.pattern) == "table") and p.pattern[1] or p.pattern - local s, e = text:find("^" .. pattern, i) + local find_results = { text:find("^" .. pattern, i) } + local start, fin = find_results[1], find_results[2] - if s then - -- matched pattern; make and add token - local t = text:sub(s, e) + if start then + -- matched pattern; make and add tokens + push_tokens(res, current_syntax, p, text, find_results) - push_token(res, current_syntax.symbols[t] or p.type, t) -- update state if this was a start|end pattern pair if type(p.pattern) == "table" then state = bit32.replace(state, n, current_level*8, 8) @@ -162,7 +195,7 @@ function tokenizer.tokenize(incoming_syntax, text, state) end -- move cursor past this token - i = e + 1 + i = fin + 1 matched = true break end diff --git a/data/plugins/language_c.lua b/data/plugins/language_c.lua index 1445d067..b311884b 100644 --- a/data/plugins/language_c.lua +++ b/data/plugins/language_c.lua @@ -5,17 +5,20 @@ syntax.add { files = { "%.c$", "%.h$", "%.inl$", "%.cpp$", "%.hpp$" }, comment = "//", patterns = { - { pattern = "//.-\n", type = "comment" }, - { pattern = { "/%*", "%*/" }, type = "comment" }, - { pattern = { "#", "[^\\]\n" }, type = "comment" }, - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = "-?0x%x+", type = "number" }, - { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, - { pattern = "-?%.?%d+f?", type = "number" }, - { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, - { pattern = "[%a_][%w_]*%f[(]", type = "function" }, - { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "//.-\n", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = "0x%x+", type = "number" }, + { pattern = "%d+[%d%.eE]*f?", type = "number" }, + { pattern = "%.?%d+f?", type = "number" }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "struct%s()[%a_][%w_]*", type = {"keyword", "keyword2"} }, + { pattern = "union%s()[%a_][%w_]*", type = {"keyword", "keyword2"} }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, + { pattern = "#include%s()<.->", type = {"keyword", "string"} }, + { pattern = "#[%a_][%w_]*", type = "keyword" }, }, symbols = { ["if"] = "keyword", @@ -29,8 +32,6 @@ syntax.add { ["continue"] = "keyword", ["return"] = "keyword", ["goto"] = "keyword", - ["struct"] = "keyword", - ["union"] = "keyword", ["typedef"] = "keyword", ["enum"] = "keyword", ["extern"] = "keyword", @@ -42,7 +43,6 @@ syntax.add { ["case"] = "keyword", ["default"] = "keyword", ["auto"] = "keyword", - ["const"] = "keyword", ["void"] = "keyword", ["int"] = "keyword2", ["short"] = "keyword2", From b278306fc94b421eaedf8764301042391ff1569b Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 19 May 2021 16:41:28 -0400 Subject: [PATCH 22/22] Changed deindent, so that if the deindent runs into an unusual line with a partial indent at the front, it'll still de-indent that. (#193) --- data/core/commands/doc.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/data/core/commands/doc.lua b/data/core/commands/doc.lua index ee930150..cf4430d3 100644 --- a/data/core/commands/doc.lua +++ b/data/core/commands/doc.lua @@ -45,15 +45,22 @@ local function insert_at_start_of_selected_lines(text, skip_empty) doc():set_selection(line1, col1 + #text, line2, col2 + #text, swap) end + -local function remove_from_start_of_selected_lines(text, skip_empty) +local function remove_from_start_of_selected_lines(text, skip_empty, remove_partial) local line1, col1, line2, col2, swap = doc_multiline_selection(true) for line = line1, line2 do local line_text = doc().lines[line] - if line_text:sub(1, #text) == text - and (not skip_empty or line_text:find("%S")) - then - doc():remove(line, 1, line, #text + 1) + for i = #text, 1, -1 do + if line_text:sub(1, i) == text:sub(1, i) + and (not skip_empty or line_text:find("%S")) + then + doc():remove(line, 1, line, i + 1) + break + end + if not remove_partial then + break + end end end doc():set_selection(line1, col1 - #text, line2, col2 - #text, swap) @@ -193,7 +200,7 @@ local commands = { ["doc:unindent"] = function() local text = get_indent_string() - remove_from_start_of_selected_lines(text) + remove_from_start_of_selected_lines(text, false, true) end, ["doc:duplicate-lines"] = function()