Commit Graph

43 Commits

Author SHA1 Message Date
hedy
8b2f412b7b fix(providers): Ensure working on nvim-0.7
This commit removed the ability to receive symbols from all attached
clients in the current buffer. Everything works as before when only one
client is attached to a buffer.

This also fixes outline LSP finding clients on nvim-0.7
2023-12-29 19:17:00 +08:00
hedy
884486f3d0 feat: Live previews (peek editor)
Disabled by default, but if this feature turns out to be useful and
stable, it will replace the old preview window.
2023-11-28 20:50:08 +08:00
hedy
3ebf0ffc69 feat: Use augroup
I had no idea augroup does all I tried to do with `self.autocmds`. Oh
well.

Also added sidebar.id, which is one step closer to #25
2023-11-28 09:38:57 +08:00
hedy
8df37421cc fix: Old preview autocmd 2023-11-27 21:11:37 +08:00
hedy
80f76333ba fix/refactor(preview): Proper per-sidebar support & complete rewrite 2023-11-27 20:08:22 +08:00
hedy
b90174c6c2 refactor: Provider symbol actions
It makes sense to store the provider each sidebar is using with own
self.provider fields, no way that did not occur to me before this.

The old `_G._outline_current_provider` ironically, can now be replaced
by `require('outline').current.provider`.
2023-11-26 15:14:42 +08:00
hedy
1743ee7c66 chore(fmt): stylua 2023-11-26 13:29:47 +08:00
hedy
137e76fdca chore(fmt): Consistent function doc style 2023-11-26 13:27:29 +08:00
hedy
9f69f12161 refactor: Reorganize modules
Primarily:
- Utils
- Sidebar (removed the need of writer.lua)
- Resolve keymaps shortcut in config eraly
- Put highlight functions into highlight.lua
- Put functions that do stuff on outline window into view.lua
2023-11-26 13:17:18 +08:00
hedy
6d85399550 feat: Use more concise API names
No breaking change.
2023-11-25 15:43:36 +08:00
hedy
6cea72f2b5 feat(api): Get symbol and breadcrumb at location
Currently the implementation is very limited.

Ref: #24

- Outline must be open and have been loaded for it to work (requires
  lazy loading or headless loading of Sidebar)
- Empty string returned if cursor is not in any symbol ('closest' symbol
  not yet supported)
- Line column not used
- Returning concatenated symbol names rather than a list of tables with
  node info (requires a refactor of outline.SymbolNode type)
- Subject to config.symbols.filter and folds (requires finding hover
  list somewhere outside of writer.make_outline)
2023-11-25 15:41:55 +08:00
hedy
842f2c4a86 refactor(status,help): Rename module and make naming more descriptive 2023-11-24 17:16:44 +08:00
hedy
ecc814f846 fix(api): Add back is_focus_in_outline 2023-11-24 17:13:59 +08:00
hedy
896fd2ae63 feat(status): Better information and highlights 2023-11-24 16:31:16 +08:00
hedy
f4d5eb2dad fix(status): Show code window active when no outline opened yet 2023-11-24 16:17:52 +08:00
hedy
a2410faba9 refactor: Rename module ui -> highlight 2023-11-24 16:10:21 +08:00
hedy
23958f8731 chore(fmt): stylua 2023-11-24 15:04:28 +08:00
hedy
e705330e40 feat: Per-tabpage outlines
Closes #37

Almost completely refactored the UI parts outline.nvim to use a Sidebar
object that implements an outline window. In init.lua, we can then store
a table of the outline for each tabpage ID.

When tabs are closed the outline is closed and sidebar reset
responsibly.

This simplifies `init.lua` quite a lot, making it the highest level
control center for the outline elements.

All lua APIs and commands should work as before.
2023-11-24 14:50:24 +08:00
hedy
699bc85cc5 feat: Properly support nvim-0.7, and fix highlights 2023-11-21 08:39:05 +08:00
hedy
9b90379c7a Refactor 2023-11-19 17:45:41 +08:00
hedy
3b27272319 feat(Status): Better provider info and show filter info 2023-11-19 16:59:49 +08:00
hedy
f8c212bcd2 docs: Document new options, commands, API functions 2023-11-18 22:24:34 +08:00
hedy
c06039da1e feat: Add refresh_outline function 2023-11-18 22:09:19 +08:00
hedy
87a72f88fa fix: Delete autocmds when wiping state 2023-11-18 21:08:13 +08:00
hedy
e56145f8dd feat: Proper floating window for keymap help and OutlineStatus
No more obnoxious '}' on the cmdline when pressing `?`!

scope:
- More type hints
- Added class Float for creating floating windows with size that fit the
  content and position centered on the screen
- show_help action for outline window (key `?`) now uses a floating
  window
- :OutlineStatus now provides better information, and shows content in a
  floating window.

future:
- Floating window option configuration
2023-11-18 20:52:50 +08:00
hedy
090da7633b fix: Preview window position based on outline split position
- preview window can adapt based on position of outline window, and not
  based on config value of `position` left/right
- it can also properly vertically center-align, even when there are
  horizontal splits below the outline
- fixed a few bugs associated with previous rewrite commits in init.lua

config:
- Added min_height for preview window
2023-11-18 15:04:26 +08:00
hedy
62183f9d51 fix: Ensure autocmds IDs are removed when deleted 2023-11-18 13:16:42 +08:00
hedy
d65696a9cf feat: Optionally not auto-update cursors position
This also fixes a typo from an old commit (did not catch the bug because
all this time I was testing with the same window!), and put
auto_update_events into outline_items since it makes more sense, and is
closer to highlight_hovered_item and (the new) auto_follow_cursor.

Added code_buf to state since it appears to be used quite often now.
2023-11-18 11:14:18 +08:00
hedy
82ab53a167 chore: stylua 2023-11-18 10:02:04 +08:00
hedy
d35ee70f95 feat: Better highlight-hover/follow-cursor procedures
Previously on each outline open, the `writer.make_outline` function
might be called at least 4 times(!), after this refactor it will only be
called once. And on update cursor autocmds, also called once (previously
at least twice).

behaviour:
- Now the outline window focus and highlight can update on each cursor
  move (previously CursorHold, dependent on updatetime). This is now
  configurable as well.

- During fold-all/unfold-all operations, now the cursor will remain on
  the same node (rather than same line in outline buffer).

- The performance improvement is not significantly observable since even
  the old implementation can appear instant. One may even argue I am
  fixing a problem that did not exist, but implementation-wise it's just
  so much better now.

config:
- outline_window.auto_update_events, list of events to be passed to
  create_user_autocmd for updating cursor focus in outline, and updating
  outline items (refetching symbols), using keys cursor and items
  respectively.

- outline_window.show_cursorline now supports 2 other string values:
  'focus_in_outline'/'focus_in_code' which controls when to enable
  cursorline. Setting to true retains the default behaviour of always
  showing the cursorline. This was added because now that the cursor
  focus on the outline could change on each CursorMoved, the cursorline
  may pose to be qute attention-seeking during the outline cursor
  updates. Hence `focus_in_outline` is added so that when focus is in
  code, the cursorline for outline window is not shown.

  'focus_in_code' is added so that a user who disabled
  highlight_hovered_item can keep track of position in outline when
  focus is in code, disabling cursorline when focus is in outline.

  At any given time, if hide cursor is enabled and show_cursorline is a
  string value, hiding of cursor will not be done if cursorline is not
  shown in the the given situation.

implementation:
- The reason for the improvement in performance as described in the
  first paragraph is due to merging of finding hover item and finding
  the deepest matched node to put cursor, into writer.make_outline. This
  done, when previously done in separate function, because after the
  separate function (namely _highlight_hovered_item) finishes,
  writer.make_outline is called *again* anyway.

- Autocmds to update cursor position in outline is now done per buffer
  rather than global.

Somehow the auto unfold and unfold depth options still work perfectly,
for this we should thank simrat or which ever contributor that
modularized the folding module and made it adaptable :)
2023-11-18 09:34:16 +08:00
hedy
a1aa652fb2 feat: Center view on jump/goto 2023-11-17 12:34:14 +08:00
hedy
dc55a8b942 chore(fmt): Finally let's use stylua
Hoping it's as good as go-fmt
2023-11-17 09:28:33 +08:00
hedy
134b7e2f39 feat: Jump highlight customizations
Closes #27

- Highlight group 'OutlineJumpHighlight' (links to Visual by default)
- Config: outline_window.jump_highlight_duration (integer for
  milliseconds, or boolean to enable/disable)
2023-11-16 22:14:47 +08:00
hedy
24680f13f7 feat: Symbol filtering config structure
This commit introduces a basic framework for symbol filtering in
outline.nvim, where users can set per-filetype kinds to filter - include
or exclude for each filetype.

As a side effect the checking of symbol inclusion function has been
improved to O(1) time-complexity (previously O(n)). You can see this
from types/outline.lua and config.lua: a lookup table is used to check
if a kind is filtered, rather than looping through a list each time.
Former takes O(1) for lookup whereas the old implementation would be
O(n) for *each* node!

The old symbols.blacklist option *still works as expected*.

The schema for the new confit is detailed in #23 and types/outline.lua.
By the way, this commit also closes #23.

These should equivalent:
    symbols.blacklist = { 'Function', 'Method' }
    symbols.filter = { 'Function', 'Method', exclude=true }
    symbols.filter = {
      ['*'] = { 'Function', 'Method', exclude=true }
    }

And these should be equivalent:
    symbols.blacklist = {}
    symbols.filter = false
    symbols.filter = nil
    symbols.filter = { ['*'] = false }
    symbols.filter = { ['*'] = { exclude = true } }
    symbols.filter = { exclude = true }

The last two of which could be considered unidiomatic.

When multiple filetypes are specified, filetype specific filters
are NOT merged with the default ('*') filter, they are independent. If a
filetype is used, the default filter is not considered. The default
filter is only considered if a filetype filter for the given buffer is
not provided.

LIMITATIONS:
This is carried over from the implementation from symbols-outline:
filters can only be applied to parents at the moment. I.e.: If some node
has a kind that is excluded, all its children will NOT be considered.

Filters are only applied to children if its parent was not excluded
during filtering.

Also extracted all types into types module, and updated conversion
script to use the new symbols.filter opt.

NOTE:
On outline open it appears that parsing functions are called twice?
I should definitely add tests soon.
2023-11-16 21:21:55 +08:00
hedy
5278eb5b2b feat: Better provider info and fix LSP deprecated warnings
- Provider priorities can now be configured through `providers.priority`

- Each provider can have a get_status() function that returns a string
  for its status. For LSP it returns the client name.

- :OutlineStatus logic refactored, together with provider checking
  functions in `providers/init.lua`

- Switch from vim.lsp.buf_get_clients to vim.lsp.get_active_clients
  (former was deprecated)

- Fixed a careless mistake from symbols-outline that seems to be an
  unreachable bug (lsp)
2023-11-16 15:41:37 +08:00
hedy
4d871ec64b refactor: Better messages 2023-11-16 14:28:29 +08:00
hedy
7c703361e9 feat: Support command modifiers on open commands 2023-11-15 22:32:33 +08:00
hedy
81ebdc5714 chore: Fix remants of rename 2023-11-15 11:28:09 +08:00
hedy
f356c29578 feat: Allow disabling icons 2023-11-15 11:21:20 +08:00
hedy
9c70b96b36 fix(highlight-hover): Set cursor in parent if child is folded
Hopefully this commit fixes #1.

- Improved algorithm that finds the items to set hover-highlight
- Now we can set cursor on the nearest parent if the leaf node is folded
  in the outline.
- Set cursor column appropriate depending on whether lineno is enabled.

API:
- parser.preorder_iter now supports an optional argument as function,
  which determines whether to explore children. By default, folded
  parents will not explore children. This can now be overridden.

Behaviour:
- If you fold a nested node and hit <C-g>, you can go back to the
  nearest parent
- The column that cursor goes to is no longer arbitrarily chosen

It appears that simrat or whoever wrote this code thought the column was
1-indexed, however it is 0-indexed, so the old code was always putting
the cursor on the 2nd column.

Now, we put it in the first column. If lineno is enabled, we set the
cursor the be at the column of lineno padding, this makes both the
lineno and the markers visible.

Unfortunately the so-called 'improved' algorithm for
_highlight_current_item is still not the best. The most optimal would be
O(n). However, to make sure we stop refactoring now that it works OK and
can already fix an issue, I will leave this to posterity.

Tested to work (for me).
2023-11-13 21:07:30 +08:00
hedy
1446bdd135 fix: Lineno alignment, hl_mode, config options
- Config
  - Renamed auto_goto -> auto_jump (because goto implies change of
    cursor focus)
  - Renamed down/up_and_goto -> down/up_and_jump

Existing config that use the old keys *WILL STILL WORK*. But users are
recommended to update to avoid inconsistency. I promise the number of
config changes like this will decrease inverse-exponentially after the
plugin refactor :)

- Docs
  - Improved wording

- Lineno
  - Fixed alignment (no way I was taking max line num of the *Outline*
    buf this whole time!)
  - Fixed appearance of lineno column hl blending if hide_cursor is one
    (please see the comment added)
2023-11-13 18:07:52 +08:00
hedy
66aecc7636 MAJOR: Complete rewrite of outline parsing into buffer lines
Scope:
- Parsing of symbol tree
- Producing the flattened tree
- Producing the lines shown in the outline based on the symbol tree
- API of exported functions for parser.lua and writer.lua

Note that the formatting of the outline remains the same as before.

Fixes:
- Guide highlights sometimes cover fold marker areas (may be related to
  the issue brought up by @silvercircle on reddit)
- Guide highlights do not work when using guide markers of different
  widths than the default (such as setting all markers to ascii chars)

All of these issues are now fixed after integrating the a parser
algorithm.

This commit introduces:
1. A better algorithm for flattening & parsing the tree in one go
2. `OutlineFoldMarker` highlight group
3. Fixed inconsistent highlighting of guides and legacy (somewhat weaker
   code), through (1).
4. Minor performance improvements
5. Type hints for the symbol tree
6. Removed several functions from writer.lua and parser.lua due to them
   being merged into writer.make_outline

This can be seen as a breaking change because functions that were
exported had altered behaviours. However I doubt these functions
actually have any critical use outside of this plugin, hence it isn't
really a breaking change as the user-experience remains the same.

The extraneous left padding on the outline window is now a relic of the
past 🎉

The old implementation, parser.get_lines used a flattened tree and was
inefficient, full of off-by-one corrections.

While trying to look for bug fixes in that function I realized it's the
sort of "if it works, don't touch it" portion of code.

Hence, I figured a complete rewrite is necessary.

Now, the function responsible for making the outline lines lives at
writer.make_outline. Building the flattened tree, getting lines, details
and linenos are now done in one go.

This is a tradeoff between modular design and efficiency.

parser.lua still serve important purposes:
- local parse_result function converts the hierarchical tables from
  provider into a nested form tree, used everywhere in outline.nvim. The
  type hint of the return value is now defined -- outline.SymbolNode
- preorder_iter is an iterator that traverses the aforementioned tree in
  pre-order style. First the parents, all the childrens, and so on until
  the last node of the root tree. This is used in writer.make_outline to
  abstract a way the traversal code from the code of making the lines.

Thanks to stack overflow I did not have to consult a DS book to figure
out the cleanest way of this traversal method without using recursion.

This, of course, closes #14 on github.

Note that another minor 'breaking' change is that previously, hl for the
guides where grouped per-character, now they are grouped together for
all the guide markers in the same line. This should not be a problem for
those who only style the fg color for guide hl. However, if you're
styling the bg color, they will now take on that bg collectively rather
than individually.

This change eliminates future maintenance burden because controlling
per-character guide highlights requires careful avoidance of off-by-one
errors.

I have tested most common features to work as before.
I may have missed particular edge cases.

Please take note of "scope" at the top of this commit message.
2023-11-13 14:19:43 +08:00
hedy
965a3842c8 MAJOR: Project rename and preparation for v1.0.0
I hope I haven't missed any for the renames!
2023-11-12 12:40:32 +08:00