Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds completion for tab-focus. #1317

Merged
merged 3 commits into from
Mar 31, 2016
Merged

Conversation

toofar
Copy link
Member

@toofar toofar commented Feb 18, 2016

This is so you can jump between tabs based on tab title or URL instead
of just index just like the buffer command in vim. Adds a b alias
for tab-focus to be more like vim too.

The method of updating the completion model (rebuild the whole thing
every time a tab is created, removed or updated) is inefficient but is
still very fast for even unreasonable numbers of open tabs.

TODO: I did a quick test and it doesn't seem to work with multiple windows.
Probably because of how I am getting the win_id. Can anyone tell me how
to get the current win_id?

Review on Reviewable

try:
index = int(index)
except ValueError:
raise cmdexc.CommandError("tab-focus takes an int or 'last' not: {}".format(index))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between checking this here and the way it was before (via the argument annotation, index: {'type': (int, 'last')}=None)?

(I didn't actually check, but they should do the exact same thing, no?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I suppose it would do the same thing. Since typing until there is only one option left then pressing enter passes a string through I was going to add a title to index lookup there for one less keypress but that seems like way too much effort. I'll change it back.

@The-Compiler
Copy link
Member

Handling multiple windows obviously is the biggest problem here, yeah. The concept of a "current window" doesn't really exist when the completions are being rebuilt, and currently there's no mechanism for the completion to let the model know the current window when the completion is being invoked.

Those are good ideas to keep in mind for #74 somewhen in the future though.

I'd suggest a slightly different approach: Don't add a completion for :tab-focus for now, but add a different :buffer command to switch to any tab (in any window).

Then you can iterate over all windows (e.g. via for win_id in objreg.window_registry:) and build a completion for all of them, using a completion category for each window.

@The-Compiler
Copy link
Member

#32 is the related issue, by the way - a :buffer command is one of the most requested features and I never got to it, so thanks for tackling this, I'm sure many will appreciate it!

@vyp
Copy link
Contributor

vyp commented Feb 18, 2016

a :buffer command is one of the most requested features and I never got to it, so thanks for tackling this, I'm sure many will appreciate it!

aye aye! ✨ 😃 👍

@toofar
Copy link
Member Author

toofar commented Feb 19, 2016

Alrighty. I changed the completion model to iterate over all windows, put tab-focus back how it was, add a new buffer command which can switch focus between windows and can work based on a substring so that you can be lazy and don't have to actually select anything in the completion widget.

@The-Compiler
Copy link
Member

So I played with this a bit - seems quite nice, but it seems the completion doesn't update correctly when I do :open -w example.com (or open new tabs in the new window).

I'll also add some line comments for some style things - thanks for this again, looking forward to it!

index: The win_id/index of the tab to focus. Or a substring
in which case the closest match will be focused.
"""
if not index or not len(index):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty strings are false in Python, so checking if not index: here is enough.

On the other hand, why not just make index mandatory by removing the =None default?

@toofar
Copy link
Member Author

toofar commented Feb 22, 2016

but it seems the completion doesn't update correctly on new windows

Yeah ... coulda sworn that worked during testing. Looks like because there is no notification of new windows (or new tabbed_browsers) the completion model never gets a chance to hook up to the new new_tab signal.

@toofar
Copy link
Member Author

toofar commented Feb 22, 2016

I cleaned up commands:buffer() and added a signal
Application.new_window() which is emited from the MainWindow.__init__()
because it looks like windows are made all over the place and the main
application is the only non-per-window object (?). Not entirely sure how elegent that is but it works better now!

@The-Compiler
Copy link
Member

I think that's the best solution - I'll leave some more line comments.

idx = int(index)
win_id = 0
active_win = objreg.get('app').activeWindow()
if not active_win == None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be if active_win is not None:

@The-Compiler
Copy link
Member

Can you please also try writing some end-to-end tests for this? You can find some inspiration in tests/integration/features/tabs.feature. You can run those locally by installing tox and optionally Xvfb (to avoid windows popping up), and then run tox -e py35 -- tests/integration/features/test_tabs.py. (or py34 if you're on a system with Python 3.4)

@toofar
Copy link
Member Author

toofar commented Mar 7, 2016

Sorry for taking so long getting back to you. Writing tests is not very motivating. Hope this addresses your concerns.

# Not sure how you enter a command without and active window...
raise cmdexc.CommandError(
"No window specified and couldn't find active window!")
win_id = active_win.win_id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an else: raise AssertionError("Unexpected index length {}".format(len(index_parts))) or so here, so there's a defined behaviour if that should ever happen (e.g. by someone changing the completion model in the future) rather than undefined behaviour?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well there is a index_parts = index.split('/', 1) at the top of the method so there really isn't going to b more than 2 parts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I missed that 😄

@toofar toofar force-pushed the tab-complete branch 3 times, most recently from 95b6229 to 7f86c61 Compare March 22, 2016 21:46
@AeliusSaionji
Copy link

fwiw, I've been @toofar 's tab-complete branch with no issues. If I try to access :buffers before the browser finishes starting up, the list will be empty, but otherwise all is good.

@The-Compiler
Copy link
Member

Thanks for letting me know! Now that the crowdfunding is up I can get back to coding and reviewing PRs, so I'll probably merge this in the coming few days.

The-Compiler added a commit that referenced this pull request Mar 26, 2016
Using -m py.test seems to cause some issues, see e.g.
#1317 (comment)
@The-Compiler The-Compiler added this to the v0.6.0 milestone Mar 29, 2016
@The-Compiler The-Compiler self-assigned this Mar 29, 2016
QTimer.singleShot(0, self.rebuild_cat)

@pyqtSlot(str)
def rebuild_cat(self, arg=None): # pylint: disable=unused-argument
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for the argument here? It seems to work fine when I use @pyqtSlot() and drop the , arg=None. Note slots can have less arguments than the signals they're connected to.

@The-Compiler
Copy link
Member

When I close a window, I still see the window category when typing :buffer until I close the next tab - I think that's just due to objreg.window_registry still containing the windows for a little bit until everything is cleaned up? Not sure if you can do much about this, though...

Could you also fix the line comments and the few nitpicks found by the linters?

************* Module qutebrowser.completion.models.miscmodels
C:187, 4: Missing method docstring (missing-docstring)
./qutebrowser/completion/models/miscmodels.py:197:37: E261 at least two spaces before inline comment

Can you also run scripts/dev/src2asciidoc.py and commit the result?

After that, I think this is ready to merge - thanks a lot!

@toofar
Copy link
Member Author

toofar commented Mar 29, 2016

When I close a window, I still see the window category when typing :buffer until I close the next tab - I think that's just due to objreg.window_registry still containing the windows for a little bit until everything is cleaned up? Not sure if you can do much about this, though...

Since I already added a tabbed_browser.new_window signal I suppose I could add a window_close signal too.

@The-Compiler
Copy link
Member

Thanks for the quick reaction!

Since I already added a tabbed_browser.new_window signal I suppose I could add a window_close signal too.

Sounds good - can you try if that helps? I'm not entirely sure (due to how window_registry works), but I think it should.

What do you think about keybindings for :set-cmd-text -s :buffer? Since we normally conform to dwb keybindings, that'd be gt, but that's already bound to :tab-focus (by @thiagowfx in #443)... I'm somewhat inclined to just change that to conform with dwb like everything else.

`buffer` takes either a tab index or a string and focuses the specified
tab. The index can be of the form [0-9]+ which will switch to the
relevant tab in the current window or [0-9]+/[0-9]+ (that is
win_id/index) which will focus the specified window before switching
tabs. If a string is passed the list of open tabs across all windows is
sorted based on title and url (just like in the completion widget) and
the top result is selected.
The buffer_troubling_args tests may look a little un-intuitive but that is
because they are testing the edge cases for the current behaviour. If these
edge cases are encountered during normal usage you are doing something wrong.
@toofar
Copy link
Member Author

toofar commented Mar 31, 2016

Turns out the model was getting rebuilt after a window closed (due to the tab_closed signal) but the categories were being created before tabbed_browser.shutting_down was checked. So that was an easy fix. (Conecting to the MainWindow.destroyed signal and setting a timer also worked.)

For the keybindings I am just using b. I'm not really a fan of most of the dwb keybindings, I would prefer them to more ... logical; to have more of grammer than almost arbitrary mnemonics.

@The-Compiler The-Compiler merged commit 3846ce1 into qutebrowser:master Mar 31, 2016
@The-Compiler
Copy link
Member

Merged - thanks for the great work, and sorry for the delays!

@The-Compiler The-Compiler mentioned this pull request Mar 31, 2016
26 tasks
@toofar toofar deleted the tab-complete branch March 31, 2016 22:56
ninewise pushed a commit to ninewise/qutebrowser that referenced this pull request Apr 5, 2016
Using -m py.test seems to cause some issues, see e.g.
qutebrowser#1317 (comment)
The-Compiler added a commit that referenced this pull request May 16, 2020
@The-Compiler
Copy link
Member

It's been a couple of years - but since a long time, we can get the current win_id for the completion, so I added :tab-focus completion based on the :buffer completion now!

@rien333
Copy link
Contributor

rien333 commented May 16, 2020

Thanks for still being committed to PRs as old as this one! I understood that the PR backlog was a bit of hurdle, so good luck with the other ones you plan to do!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants