qutebrowser / qutebrowser

A keyboard-driven, vim-like browser based on Python and Qt.
https://www.qutebrowser.org/
GNU General Public License v3.0
9.48k stars 1.01k forks source link

Tree style tabs #927

Open The-Compiler opened 8 years ago

The-Compiler commented 8 years ago

ye8

Like the tree style tabs Firefox addon.

ivanbalashov239 commented 8 years ago

killer feature the only one reason why i use firefox

skrzyp commented 8 years ago

:+1: this :+1:

NoSuck commented 8 years ago

Today I learned that, while I sometimes think I have many tabs open, there are perhaps people with many, many more.

ivanbalashov239 commented 8 years ago

@The-Compiler is it hard to implement tree style tabs? will you do it?

The-Compiler commented 8 years ago

is it hard to implement tree style tabs?

Hard to say - the basics of indenting pages should be relatively easy, but then there are other things like collapsing/expanding, handling the tree in sessions, etc.

will you do it?

Will you? :wink:

I will at some point, but I don't need this functionality myself and I have other priorities right now - so it'll likely take a few months until I get to it.

Xananax commented 8 years ago

Just giving my +1 to this; I typically browse to research something, and it's not uncommon for me to have 100+ tabs open, all neatly organized in trees so I don't have to remember why I opened such or such tab.
Even just indenting the child tabs (without advanced options such as folding a tree or options for how should child tabs behave when parent is closed) would go a long way into providing more structure when having a lot of tabs open.

An (ugly, but functional) alternative would be to assign a random color to all tabs that are from the same parent. There's a FFx addon that does that too; assign a random color to all parent tabs then assign an increasingly lighter color for child tabs (so, parent tab, dark blue, child tab, lighter blue, child of child, even lighter blue).

ziekke commented 7 years ago

I'd just like to leave a support +1 for this feature. It's become almost mandatory for me to have tree-style tabs at this point since I started using it with Firefox. I'd like to transition to qute but this feature would be sorely missed.

odecay commented 7 years ago

Would this be something that would be possible to write using the current userscript system? I'd be interested in trying, but don't know where to start.

The-Compiler commented 7 years ago

@sitonapanotis You posted your comment ~25 times, I deleted the others now - if you have a customized user agent, you'll need to set it back to the default for GitHub to work correctly :wink:

It's not possible to implement this via an userscript, no. I'm not sure how much effort it'd be to implement in qutebrowser's core (i.e., in Python).

There are already vertical tabs, and from what I've gathered here the main feature people are missing is the indenting of related tabs, correct? I think that should be relatively straightforward to implement for someone knowing a bit of Python. If someone wants to step up, I'm happy to help.

odecay commented 7 years ago

@The-Compiler sorry about that, I was using a chrome user agent to make inbox.google.com work, changed back now. I'll have a look at the code and start trying to figure out whether this is something I can realistically work on.

The-Compiler commented 7 years ago

Some pointers:

I'm not sure what would happen when you move an indented tab to a new position, or probably some other corner cases like that... I guess the affected tab would lose their indent then?

Xananax commented 7 years ago

Behavior in TreeStyleTabs (for reference):

DnD:

When a tab with children is closed, behavior is either (depending on user options):

Opening a link in a new tab:

Creating a tab (depends on how it's opened):

A simplified version for QB could be to:

I think this would cover all the bases with just one added property, no messing about with groups and drop targets and what not.

I haven't thought lengthily about this nor have I ever implemented anything similar, but I think it could work.

As a matter of fact, I'd be ok with just an "indent" property that I must manipulate myself, as long as I can do it for multiple tabs at a time. It would be sufficient to differentiate tabs visually.

The-Compiler commented 7 years ago

@Xananax Thanks for the great overview! This definitely seems less simple to get correct than I initially thought :wink:

m2habert commented 7 years ago

1788 helps TST usage / idea, methinks

"(tabAttach) also comes in handy when skimming while researching for reading later. It is quite common for the user to, when interested in a given subject (like "mmmm, ¿should I move from Vimperator to this new QB novel?"), jump to opening dozens of pages on the matter with the help of google (and from those open another dozen of links), only to skim the general info and possibly save part of them for in-depth info later. With tabAttach one can easily move pages between a window for "input", another for "done deal" and a third one for "read thoroughly later" "

The-Compiler commented 7 years ago

Could you rephrase "greatly informs TST usage / idea"? I don't understand what you're trying to say with that.

m2habert commented 7 years ago

I guess it's a pompous way of saying "it helps the functionality that TST brings / promotes", in the sense that, if one is going to expect tabs nested in a hierachical tree, moving those trees and / or tabs between windows comes in handy.

Xananax commented 7 years ago

Not sure if I should open another feature request for this, but a different way of implementing a similar functionality (for me, at least), is to implement the same thing as Firefox workspaces: named groups of tabs.

I use tree style tabs to switch contexts; example: I'm answering emails, and I remember I need to check this new framework. I do a google search for it in a new tab and open a few articles, then collapse the mother tab to get those out of the way. Later, at lunch, I'll come back to those, deepen my research, then collapse all again to get back to work; etc. Some of my collapsed tabs sleep for weeks, until I get back to them (I always do).

Any way of grouping tabs together, hide them and recall them (without reloading) would work for me.

Since I feel the basic need can be fulfilled by either tree style tabs or groups, I'm not opening a new issue, but I'm not sure if that's the only thing people use tree style tabs for.

DIzFer commented 7 years ago

That would only cover part of the usecase. What you described is closer to Firefox's Panorama/Tab Groups, or Vivaldi's Tab Stacks. Trees are a very different visualization, they provide origin information in addition to just context, and they are both visually integrated into the normal tabs and distinctive. Tab Groups are too big of a separation, and Stacks make them too compact for my taste.

Xananax commented 7 years ago

Yea I agree they're kinda different, but there's overlap. It's just, any way to organize tabs as related (even something as simple as just assigning colors) would instantly make QB much more useful to me, so I'm throwing out there all the possibilities in case something is easier to implement than tree style tabs.

I agree that this may warrant a different feature request, but in my personal case, I wouldn't care much for groups if there was a tree.

dotancohen commented 7 years ago

Xananax: Overlap or no, that is a different feature. Your last sentence makes that perfectly clear!

By the way, Tree Style Tabs is what has me stuck on Firefox though I would have left years ago it any other browser supported it. Of course, the only other thing that Firefox has going for it is Vimperator, so once this feature is implemented I'll be the first to start using and promoting qutebrowser.

Thanks.

terlar commented 7 years ago

Another example of a browser with Tree Style Tabs is https://github.com/kovidgoyal/vise

It is also written in python, so perhaps could draw some inspiration.

dotancohen commented 7 years ago

Note that the afore-mentioned Vise is developed by the same person who develops the excellent Calibre ebook manager.

However he considers Vice to be a hobby, not for public consumption. It would be nice to take the tree view from Vice into qutebrowser.

[1] https://calibre-ebook.com/

vlcek commented 6 years ago

Just wanted to mention that I'm toying with this feature in qutebrowser. I'm really missing tree tabs from firefox so I somehow managed to get them in qutebrowser :-)

Code is horrible right now (I'm not used to python and object oriented code anymore) and it is quite buggy for now. However here is screencast how it is working right now :-)

Any comments and ideas are welcome. qutebrowser_treetab

ivanbalashov239 commented 6 years ago

@vlcek that's awesome news, you should make it public, so those who interested could help you.

skrzyp commented 6 years ago

OH. MY. GOD.

I think I'm not the only person who'll actually donate you for releasing & finishing this feature.

jgkamat commented 6 years ago

@vlcek I would be willing to help with testing/developing this as well, in the interest of trying to get this 'usable' before Firefox deprecates their plugin system (which breaks the tree style tabs plugin). If you could publish what you have in a fork that would be awesome :).

Firefox 57 (the first one to deprecate such addons) is scheduled to release in November.

m2habert commented 6 years ago

@vicek That's amazing.

I would like to pinpoint one of the features (or maybe it's an accidental feature) of TST that I'm keen on: the specific "about" url that accepts any string and renders a "nice-enough" looking page. (Sorry if this is obvious to all TST fans, but I never read elsewhere anybody describing this particular goodie). The folllowing:

about:treestyletab-group?

can be used as "divider" between many tabs and/or an customizable "marker/freezer" of any page.

In other words, imagine that in a initial moment of a given research one opens several windows with many tabs each to be read and compared. As the user progresses in reading / research, he/she can close/pin a tab by opening :

about:treestyletab-group? ‹‹ Done Deal

or

about:treestyletab-group? Good analisys on foo (lacking on bar)

or even, as a divider :

about:treestyletab-group? ⇣ these here great ⇡ these here not quite

...Resulting in a visual annotation of the work that preserves everything (as the user can always go back in history on each "about:")

This is also a neat way of canceling heavy pages to preserve the browser responsiveness, as a proccessing offending page (I'm looking at you, Facebook!) can be nicely "masked" under an open: about:treestyletab-group? ‹‹ READ LATER which, incidentally, can be mapped to any keystroke under the vimperator/qutebrowser/vimish logic.

(I avoided to burden this thread with such prolixic description in the past because "about:" in qutebrowser was working just the same, preserving history and all. But at some point that ceased to be and now with @vicek 's contribution I thought that it would be a good point to present the case for such functionality.)

(an example of a session of mine:

screen shot 2017-08-28 at 16 58

)

vlcek commented 6 years ago

Oh, I didn't know that they are planning to deprecate it so soon. I consider it just as a proof of concept and a toy project of mine.

Some comments to the code I have now:

Tree tabs are hardcoded (there no options to turn them off) and there is actually no support for tabs history. I am using tree data strucutre (anytree package) for storing tree tab structure. I have modified tab title update function to reflect the shape of the tree structure. Therefore all modifications of the tree are reflected in tabs as a title change.

I will release the code in brach after I make some comments. I hope it won't take long :)

vlcek commented 6 years ago

Here is link to my fork of qutebrowser. I don't have much time lately so I would be gratefull if somebody else could help me finishing it :)

https://github.com/vlcek/qutebrowser/commit/7a2076fe1024e0bf04aeaa895d68e2860cc23c2e

vlcek commented 6 years ago

@m2habert Wow, that's an amazing feature I didn't know about at all!

However, I think it is "bonus" feature which should be done after we have fully functional tree tabs.

IMHO it is time to make some kind of feature TODO list before some of the great ideas get lost. Is there anybody willing to make such list? I don't know when I get to it.

The-Compiler commented 6 years ago

I'd say we can worry about that (and open a new issue) once the basic functionality is in. I'm happy to go through the comments here once that's the case.

FWIW, the about:treestyletab-group? stuff would probably be a command with qutebrowser.

Xananax commented 6 years ago

@vlcek

I would be gratefull if somebody else could help me finishing it :)

What is it that you need? Can you write a short list?

I don't think I can help, but if there's a succinct list of points, I might find that there's something that is in my means; more importantly, other people may

m2habert commented 6 years ago

@m2habert Wow, that's an amazing feature I didn't know about at all!

@vlcek That combined with vimperator's :tabattach and dettach (plus session saving/loading) make for a killer organizational method.

If we summ that with #2642 getting implemented with across-tab and across-window scope the way @braham-snyder suggested... I'll be in nerd heaven. :-P :-P

kepi commented 6 years ago

I fixed one bug which made tree tabs unusable for me (new tabs were sometimes created in root instead under current tab - more in commit log). Not sure if I didn't break anything else :) but looks ok so far. I also did some polishing so I can get around the code better.

I'll be keeping current "working" version in feature/tree-tabs branch in my repo. I'm adding new stuff to requirements too so don't forget to run something like tox -r -e mkvenv (or your equivalent).

It seams at least usable - I was able to finally switch from Firefox. Couple important things are missing for real usage:

  1. most important - saving and restoring tab tree with session
  2. creating new tab at root level - every tab is created under current tab now. You can promote it manually at least.
  3. moving tab down in current level. Only possibility is up now (with tree-tab-rotate-up command (key zu)
  4. add config switch to enable/disable probably? What should be default?
  5. change default keybindings

@vlcek bound promoting to zp, demoting to zu only to test it. For daily use I'm using:

tree-tab-promote
    <alt-h>

tree-tab-demote
    <alt-l>

Btw @m2habert made me really unhappy. I didn't notice treestyletab-group at all in more than year of using TST. Now I'm not sure if I can't live without it :)

m2habert commented 6 years ago

Btw @m2habert made me really unhappy. I didn't notice treestyletab-group at all in more than year of using TST. Now I'm not sure if I can't live without it :)

@kepi You can hack it on qB with :open k:foo_bar_qux or :open back:foo_bar_qux or :open done:foo_bar_qux...

I mean, any string:string generates an error page that has the string as title.

Can't use space or special chars, and it's not as pretty... but it's still useful.

(Call me crazy, but I use "k:" as the closest to a left arrow and "v:" as a down one. Mapped them to zk and zv.

(more precisely, I mapped "zk" to yank -ts ;; set-cmd-text :open k:{clipboard} then I go back and sub part of the title's spaces with underscores) )

pkillnine commented 6 years ago

I updated @kepi 's tree-style tabs branch (https://github.com/kepi/qutebrowser/tree/feature/tree-tabs) for the latest qutebrowser and so far it seems to work, it just required putting keybindings in the new configdata.yml, changing a method call name (update_tab_title) and changing a variable name from explicit to relative. It's a little messy, I commented out some stuff that was created when I ran git apply --3way and left it in there, but for anyone who wants it here it is.

Note: requires the python package anytree.

To apply the patch, just copy it into a file, and then change to the qutebrowser directory and run git apply /path/to/patch.diff.

diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index 141555290..bc9339505 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -32,6 +32,7 @@ from qutebrowser.utils import utils, objreg, usertypes, log, qtutils
 from qutebrowser.misc import miscwidgets, objects
 from qutebrowser.browser import mouse, hints

+from anytree import Node

 tab_id_gen = itertools.count(0)

@@ -645,6 +646,12 @@ class AbstractTab(QWidget):
         # self.elements = AbstractElements(self)
         # self.action = AbstractAction()

+        # we assume the parent always exists if using tree tabs
+        if parent:
+            self.node = Node(self, parent = parent.tree_root)
+        else:
+            self.node = Node(self, parent = None)
+
         self.data = TabData()
         self._layout = miscwidgets.WrapperLayout(self)
         self._widget = None
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
index 8f5019499..baeb357c4 100644
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -83,6 +83,7 @@ class CommandDispatcher:
         """Convenience method to set the current widget index."""
         cmdutils.check_overflow(idx, 'int')
         self._tabbed_browser.setCurrentIndex(idx)
+        self._tabbed_browser.print_tree_tab_structure("---- Printing from Command _set_current_index ----\n")

     def _current_index(self):
         """Convenience method to get the current widget index."""
@@ -2195,3 +2196,92 @@ class CommandDispatcher:
             window.showFullScreen()
         log.misc.debug('state before fullscreen: {}'.format(
             debug.qflags_key(Qt, window.state_before_fullscreen)))
+
+    @cmdutils.register(instance='command-dispatcher', scope='window')
+    def tree_tab_print(self):
+        """Test
+
+        Args:
+
+        """
+        self._tabbed_browser.print_tree_tab_structure("---- Printing from Command tree_tab_printf----\n")
+
+    @cmdutils.register(instance='command-dispatcher', scope='window')
+    def tree_tab_promote(self):
+        """Test
+
+        Args:
+
+        """
+
+        tab = self._current_widget()
+
+        grandparent = tab.node.parent.parent
+
+        if grandparent:
+            tab.node.parent = grandparent
+
+
+        #idx = self._tabbed_browser.indexOf(tab)
+        #self._tabbed_browser._update_tab_title(idx)
+        self._tabbed_browser._update_tab_titles()
+        self._tabbed_browser.update_tree_tab_positions('command: tree_tab_promote')
+
+    @cmdutils.register(instance='command-dispatcher', scope='window')
+    def tree_tab_demote(self):
+        """Tets
+
+        Args:
+        """
+
+        cur_node = self._current_widget().node
+
+        # always assume there is a parent
+        siblings = list(cur_node.parent.children)
+
+        if siblings and len(siblings) > 1:
+
+            # we want upper tab in the same subtree as current node
+            node_idx = siblings.index(cur_node) - 1
+
+            if node_idx >= 0:
+
+                cur_node.parent = siblings[node_idx]
+
+                self._tabbed_browser._update_tab_titles()
+                self._tabbed_browser.update_tree_tab_positions('command: tree_tab_demote')
+
+    @cmdutils.register(instance='command-dispatcher', scope='window')
+    def tree_tab_rotate_up(self):
+        """Tets
+
+        Args:
+        """
+        node = self._current_widget().node
+
+        parent = node.parent
+        siblings = list(parent.children)
+
+        if siblings:
+            siblings.append(siblings.pop(0))
+
+            parent.children = siblings
+
+        self._tabbed_browser.update_tree_tab_positions('command: tree_tab_rotate_up')
+
+    @cmdutils.register(instance='command-dispatcher', scope='window')
+    def tree_tab_next_on_same_level(self):
+
+        cur_node = self._current_widget().node
+
+        # always assume there is a parent
+        siblings = list(cur_node.parent.children)
+
+        if siblings and len(siblings) > 1:
+
+            # we want upper tab in the same subtree as current node
+            node_idx = siblings.index(cur_node)
+
+            next_node = siblings[node_idx+1]
+
+            self._set_current_index(self._tabbed_browser.indexOf(next_node.name))
diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml
index 39c8ec226..7777c652a 100644
--- a/qutebrowser/config/configdata.yml
+++ b/qutebrowser/config/configdata.yml
@@ -2062,6 +2062,9 @@ bindings.key_mappings:
 bindings.default:
   default:
     normal:
+      zp: tree-tab-promote
+      zd: tree-tab-demote
+      zu: tree-tab-rotate-up
       <Escape>: clear-keychain ;; search ;; fullscreen --leave
       o: set-cmd-text -s :open
       go: set-cmd-text :open {url:pretty}
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py
index 48803f1c8..d1d4f585d 100644
--- a/qutebrowser/mainwindow/tabbedbrowser.py
+++ b/qutebrowser/mainwindow/tabbedbrowser.py
@@ -337,6 +337,33 @@ class TabbedBrowser(tabwidget.TabWidget):
                                   tab.data.pinned)
                 self._undo_stack.append(entry)

+        cur_node = tab.node
+
+        node_parent   = cur_node.parent
+
+        if node_parent:
+
+            node_siblings = list(node_parent.children)
+            node_children = cur_node.children
+
+            if node_children:
+                next_node = node_children[0]
+
+                # prvni node se stane parentem pro ostatní děti
+                for n in node_children[1:]:
+                    n.parent = next_node
+
+                # swap nodes
+                node_idx = node_siblings.index(cur_node)
+                node_siblings[node_idx] = next_node
+
+                node_parent.children = tuple(node_siblings)
+                cur_node.children = tuple()
+
+            cur_node.parent = None
+        else:
+            self.print_tree_tab_structure("!!! ERROR !!! Tab ID %s\n" % tab.tab_id)
+
         tab.shutdown()
         self.removeTab(idx)
         if not crashed:
@@ -457,8 +484,16 @@ class TabbedBrowser(tabwidget.TabWidget):
                                 parent=self)
         self._connect_tab_signals(tab)

-        if idx is None:
-            idx = self._get_new_tab_idx(related)
+#<<<<<<< ours
+#        if idx is None:
+#            idx = self._get_new_tab_idx(related)
+#=======
+        # this was necessary to remove otherwise it was making a hell of a mess in tree structure
+        # if idx is None:
+        #     idx = self._get_new_tab_idx(explicit)
+        idx = self._get_new_tab_idx(related)
+
+#>>>>>>> theirs
         self.insertTab(idx, tab, "")

         if url is not None:
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
index d0a273754..918290646 100644
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -33,13 +33,25 @@ from qutebrowser.utils import qtutils, objreg, utils, usertypes, log
 from qutebrowser.config import config
 from qutebrowser.misc import objects

+# FIXME: only for debugging - remove before releasing
+# import ipdb

 PixelMetrics = usertypes.enum('PixelMetrics', ['icon_padding'],
                               start=QStyle.PM_CustomBase, is_int=True)

+from anytree import Node, PreOrderIter, RenderTree, AsciiStyle, AbstractStyle

-class TabWidget(QTabWidget):

+class TreeTabStyle(AbstractStyle):
+    """Class used only to set style of tree guidelines
+    """
+
+    def __init__(self):
+        super(TreeTabStyle, self).__init__(u'\u2502  ',
+                                        u'\u251c\u2500 ',
+                                        u'\u2514\u2500 ')
+
+class TabWidget(QTabWidget):
     """The tab widget used for TabbedBrowser.

     Signals:
@@ -70,6 +82,9 @@ class TabWidget(QTabWidget):
         self._init_config()
         config.instance.changed.connect(self._init_config)

+        # root of the tab tree, common for all tabs in the window
+        self.tree_root = Node(None)
+
     @config.change_filter('tabs')
     def _init_config(self):
         """Initialize attributes based on the config."""
@@ -144,7 +159,17 @@ class TabWidget(QTabWidget):

         fields = self.get_tab_fields(idx)
         fields['title'] = fields['title'].replace('&', '&&')
-        fields['index'] = idx + 1
+
+        # TODO move to custom TreeTab class as a function with memoziation
+        tree_prefixes = [pre[3:] for pre, _, _ in RenderTree(self.tree_root, style=TreeTabStyle)]
+
+        # probably a hack, I believe there is a better way to check if the window and the first tab is initialized before tree root
+        if len(tree_prefixes) > self.count():
+            tree_prefix = tree_prefixes[idx+1]
+        else:
+            tree_prefix = ""
+
+        fields['index'] = tree_prefix + str(idx + 1)

         title = '' if fmt is None else fmt.format(**fields)
         self.tabBar().setTabText(idx, title)
@@ -198,6 +223,32 @@ class TabWidget(QTabWidget):
         for idx in range(self.count()):
             self._update_tab_title(idx)

+    def print_tree_tab_structure(self, notes=""):
+        """A debugging function for logging state of the tree tabs"""
+        with open("qutebrowser_treetab.log", 'a') as f:
+
+            f.write("%s" % notes)
+
+            cur_tab = self.tabBar()._current_tab()
+
+            for pre, _, node in RenderTree(self.tree_root, style=AsciiStyle()):
+                name = node.name.tab_id if node.name else 'ROOT'
+                curr = '*' if cur_tab and cur_tab.node == node else ''
+
+                f.write("%s%s%s\n" % (pre, name, curr))
+
+            f.write("\n")
+
+    def update_tree_tab_positions(self, caller_info):
+        """Update tab positions acording tree structure"""
+        for idx, node in enumerate(PreOrderIter(self.tree_root)):
+            if idx > 0:
+                cur_idx = self.indexOf(node.name)
+                self.tabBar().moveTab(cur_idx, idx-1)
+
+        # debbuging
+        self.print_tree_tab_structure("---- Tree Tab Update ---- " + caller_info + "\n")
+
     def tabInserted(self, idx):
         """Update titles when a tab was inserted."""
         super().tabInserted(idx)
@@ -208,6 +259,8 @@ class TabWidget(QTabWidget):
         super().tabRemoved(idx)
         self._update_tab_titles()

+        self.update_tree_tab_positions('tabRemoved')
+
     def addTab(self, page, icon_or_text, text_or_empty=None):
         """Override addTab to use our own text setting logic.

@@ -255,6 +308,9 @@ class TabWidget(QTabWidget):
         Return:
             The index of the newly added tab.
         """
+
+        cur_tab = self.tabBar()._current_tab()
+
         if text_or_empty is None:
             icon = None
             text = icon_or_text
@@ -263,7 +319,19 @@ class TabWidget(QTabWidget):
             icon = icon_or_text
             text = text_or_empty
             new_idx = super().insertTab(idx, page, icon, '')
+
         self.set_page_title(new_idx, text)
+
+        new_node = self.widget(new_idx).node
+
+        if cur_tab and cur_tab != self.widget(new_idx):
+            new_node.parent = cur_tab.node
+        else:
+            new_node.parent = self.tree_root
+
+        # positions cannot be changed before setting the title
+        self.update_tree_tab_positions('insertTab')
+
         return new_idx

     @pyqtSlot(int)
diff --git a/requirements.txt b/requirements.txt
index 6a4739aba..7c4b68372 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,3 +8,6 @@ MarkupSafe==1.0
 Pygments==2.2.0
 pyPEG2==2.15.2
 PyYAML==3.12
+anytree==2.2.1
+# FIXME: only for debugging - remove before releasing
+ipdb
tgy commented 6 years ago

Are you thinking about merging the feature to master? Thank you all for the collaborative work 😄

The-Compiler commented 6 years ago

@tgy Only if someone works on cleaning it up and making it work without the anytree dependency. I don't have the time to do that currently.

kepi commented 6 years ago

this is not ready for merge yet at all. It is usable somehow but there are important things missing. Consider it only sort of proof of concept.

@The-Compiler anytree dependency is a problem? Should we rewrite it without it? I think it will add unneded complexicity but we will see.

The-Compiler commented 6 years ago

@kepi Yes - it's not packaged in any of the Linux distributions I've checked, so every distribution would have to package it just for qutebrowser. Qt already has QStandardItemModel/QAbstractItemModel which can be used as a tree structure - alternatively, everything we need from a tree (really just nodes with a parent and children) should be quite easy to implement in Python.

vlcek commented 6 years ago

@The-Compiler I've used it mainly for prototyping and to save some work in implementing those structures myself.

It's not big problem and also a nice exercise, but I consired it unnecessary. If you say so, we will do it :-) It will make also some features easier to implement.

ghost commented 6 years ago

NICE!!!

The-Compiler commented 6 years ago

QupZilla/Falkon might also have some inspiration for this:

http://blog.qupzilla.com/2018/02/introducing-new-extension-vertical-tabs.html https://github.com/KDE/falkon/tree/master/src/plugins/VerticalTabs

The-Compiler commented 6 years ago

3943 also has some thoughts of it with some alternative proposals, though I'm not sure how well those would work out in practice.

m2habert commented 6 years ago

( @vlcek @kepi @Yodzorah)

I've just noticed a possibility of a hack days ago that, although marginally related to this thread, could add / contribute to the general list of ideas on hierarchy of tabs and organizing.

(sorry if I derail the thread, but I thought that users keen to the TST feature could really benefit from this little thingy)

The hack would be :

:buffer =

99% of search engines use the char "=" in their urls. And as an user starts opening and searching in tabs and windows, those search result pages become cornerstones of the research output, main anchors of reference in a fast growing "mess of tabs".

So, if ones maps whatever keybind to ":buffer =" , one can have an instantaneous list of ALL search result pages, across all windows, ready to check or navigate to. All that in a simple key press.

Again, sorry for derailing the thread (but I'm genuinely excited for this little find).

But, on another hand, the concept could be polished into the TST logic, like an "automatically make any search result page a parent node"; or "list all search 'results' trees'", etc

screen shot 2018-06-14 at 11 10 05

HeathNaylor commented 5 years ago

Is the development on this feature considered halted at this point? Are we looking for someone to contribute and remove the anytree dependency?

ivanbalashov239 commented 5 years ago

@HeathNaylor looks like that

The-Compiler commented 5 years ago

Pretty much that, yeah (though the current bottleneck is mostly reviewing contributions). But as usual, as long as nobody picks things up, it won't get done :wink:

pinusc commented 5 years ago

Hi, I currently have a lot of free time on my hands, and I'd love to see this feature come to life again. I want to contribute! Where should I start?

jgkamat commented 5 years ago

Giuseppe Stelluto writes:

Hi, I currently have a lot of free time on my hands, and I'd love to see this feature come to life again. I want to contribute! Where should I start?

Right now, there's quite a large backlog of PRs that need to be merged, the best contribution that people can make is providing reviews for existing PRs.

If you want to work on this directly though, the starting point would probably be updating the patch linked in this issue to work on latest master without the anytree dependency, adding tests, and making sure it's clean/stable.