aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorinwit <inwit@sindominio.net>2024-01-29 20:45:47 +0100
committerRobin Jarry <robin@jarry.cc>2024-01-29 22:45:25 +0100
commit0c2af2e354541632c708a1a7d6eb04c1e2a951ae (patch)
tree94bf8c468cc2ab423294630055a696dbb3a8014e
parentc48d27b07b90fab54198287c552646607f401228 (diff)
downloadaerc-0c2af2e354541632c708a1a7d6eb04c1e2a951ae.tar.gz
ui: allow thread arrow customization
The thread prefix appearance is inspired by mutt and has been regarded by some as too wide and not very aesthetically pleasing. Nevertheless, it has some technical limitations, like not being able to show if a thread is folded. Allow for full customisation of the thread prefix by introducing 14 new config options. Dirlist is not affected. Changelog-added: Thread arrow prefixes are now fully configurable. Co-authored-by: Robin Jarry <robin@jarry.cc> Signed-off-by: inwit <inwit@sindominio.net> Tested-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
-rw-r--r--app/dirtree.go4
-rw-r--r--app/msglist.go91
-rw-r--r--config/aerc.conf98
-rw-r--r--config/ui.go15
-rw-r--r--doc/aerc-config.5.scd123
5 files changed, 311 insertions, 20 deletions
diff --git a/app/dirtree.go b/app/dirtree.go
index 559a717e..ce9bd27e 100644
--- a/app/dirtree.go
+++ b/app/dirtree.go
@@ -347,7 +347,9 @@ func (dt *DirectoryTree) countVisible(list []*types.Thread) (n int) {
func (dt *DirectoryTree) displayText(node *types.Thread) string {
elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator())
- return fmt.Sprintf("%s%s%s", threadPrefix(node, false, false), getFlag(node), elems[countLevels(node)])
+ return fmt.Sprintf("%s%s%s",
+ threadPrefix(node, false, false),
+ getFlag(node), elems[countLevels(node)])
}
func (dt *DirectoryTree) getDirectory(node *types.Thread) string {
diff --git a/app/msglist.go b/app/msglist.go
index 7948e6a1..63089536 100644
--- a/app/msglist.go
+++ b/app/msglist.go
@@ -417,36 +417,89 @@ func unreadInThread(thread *types.Thread, store *lib.MessageStore) (ctr int) {
return
}
-func threadPrefix(t *types.Thread, reverse bool, point bool) string {
- var arrow string
- var tip string
- if point {
- tip = ">"
- }
- arrowPrefixSibling := "├─" + tip
- arrowPrefixReverse := "┌─" + tip
- arrowPrefixEnd := "└─" + tip
- arrowStem := "│"
- arrowIndent := strings.Repeat(" ", runewidth.StringWidth(arrowPrefixSibling)-1)
+func threadPrefix(t *types.Thread, reverse bool, msglist bool) string {
+ uiConfig := SelectedAccountUiConfig()
+ var tip, prefix, firstChild, lastSibling, orphan string
+ if msglist {
+ tip = uiConfig.ThreadPrefixTip
+ } else {
+ threadPrefixSibling := "├─"
+ threadPrefixReverse := "┌─"
+ threadPrefixEnd := "└─"
+ threadStem := "│"
+ threadIndent := strings.Repeat(" ", runewidth.StringWidth(threadPrefixSibling)-1)
+
+ switch {
+ case t.Parent != nil && t.NextSibling != nil:
+ prefix += threadPrefixSibling
+ case t.Parent != nil && reverse:
+ prefix += threadPrefixReverse
+ case t.Parent != nil:
+ prefix += threadPrefixEnd
+ }
+
+ for n := t.Parent; n != nil && n.Parent != nil; n = n.Parent {
+ if n.NextSibling != nil {
+ prefix = threadStem + threadIndent + prefix
+ } else {
+ prefix = " " + threadIndent + prefix
+ }
+ }
+
+ return prefix
+ }
+
+ if reverse {
+ firstChild = uiConfig.ThreadPrefixFirstChildReverse
+ lastSibling = uiConfig.ThreadPrefixLastSiblingReverse
+ orphan = uiConfig.ThreadPrefixOrphanReverse
+ } else {
+ firstChild = uiConfig.ThreadPrefixFirstChild
+ lastSibling = uiConfig.ThreadPrefixLastSibling
+ orphan = uiConfig.ThreadPrefixOrphan
+ }
+
+ var hiddenOffspring bool = t.FirstChild != nil && t.FirstChild.Hidden > 0
+ var parentAndSiblings bool = t.Parent != nil && t.NextSibling != nil
switch {
- case t.Parent != nil && t.NextSibling != nil:
- arrow += arrowPrefixSibling
- case t.Parent != nil && reverse:
- arrow += arrowPrefixReverse
+ case parentAndSiblings && hiddenOffspring:
+ prefix = uiConfig.ThreadPrefixHasSiblings +
+ uiConfig.ThreadPrefixFolded
+ case parentAndSiblings && t.FirstChild != nil:
+ prefix = uiConfig.ThreadPrefixHasSiblings +
+ firstChild + tip
+ case parentAndSiblings:
+ prefix = uiConfig.ThreadPrefixHasSiblings +
+ uiConfig.ThreadPrefixLimb +
+ uiConfig.ThreadPrefixUnfolded + tip
+ case t.Parent != nil && hiddenOffspring:
+ prefix = lastSibling + uiConfig.ThreadPrefixFolded
+ case t.Parent != nil && t.FirstChild != nil:
+ prefix = lastSibling + firstChild + tip
+ case t.Parent != nil && t.FirstChild == nil:
+ prefix = lastSibling + uiConfig.ThreadPrefixLimb + tip
case t.Parent != nil:
- arrow += arrowPrefixEnd
+ prefix = lastSibling + uiConfig.ThreadPrefixUnfolded +
+ uiConfig.ThreadPrefixTip
+ case t.Parent == nil && hiddenOffspring:
+ prefix = uiConfig.ThreadPrefixFolded
+ case t.Parent == nil && t.FirstChild != nil:
+ prefix = orphan
+ case t.Parent == nil && t.FirstChild == nil:
+ prefix = uiConfig.ThreadPrefixLone
}
for n := t.Parent; n != nil && n.Parent != nil; n = n.Parent {
if n.NextSibling != nil {
- arrow = arrowStem + arrowIndent + arrow
+ prefix = uiConfig.ThreadPrefixStem +
+ uiConfig.ThreadPrefixIndent + prefix
} else {
- arrow = " " + arrowIndent + arrow
+ prefix = " " + uiConfig.ThreadPrefixIndent + prefix
}
}
- return arrow
+ return prefix
}
func sameParent(left, right *types.Thread) bool {
diff --git a/config/aerc.conf b/config/aerc.conf
index 30c3c7bb..ac2a6847 100644
--- a/config/aerc.conf
+++ b/config/aerc.conf
@@ -335,6 +335,104 @@
# Default: 50ms
#client-threads-delay=50ms
+#
+# Thread prefix customization:
+
+#
+# Customize the thread prefix appearance by selecting the arrow head.
+#
+# Default: ">"
+#thread-prefix-tip = ">"
+
+#
+# Customize the thread prefix appearance by selecting the arrow indentation.
+#
+# Default: " "
+#thread-prefix-indent = " "
+
+#
+# Customize the thread prefix appearance by selecting the vertical extension of
+# the arrow.
+#
+# Default: "│"
+#thread-prefix-stem = "│"
+
+#
+# Customize the thread prefix appearance by selecting the horizontal extension
+# of the arrow.
+#
+# Default: ""
+#thread-prefix-limb = ""
+
+#
+# Customize the thread prefix appearance by selecting the folded thread
+# indicator.
+#
+# Default: ""
+#thread-prefix-folded = ""
+
+#
+# Customize the thread prefix appearance by selecting the unfolded thread
+# indicator.
+#
+# Default: ""
+#thread-prefix-unfolded = ""
+
+#
+# Customize the thread prefix appearance by selecting the first child connector.
+#
+# Default: ""
+#thread-prefix-first-child = ""
+
+#
+# Customize the thread prefix appearance by selecting the connector used if
+# the message has siblings.
+#
+# Default: "├─"
+#thread-prefix-has-siblings = "├─"
+
+#
+# Customize the thread prefix appearance by selecting the connector used if the
+# message has no parents and no children.
+#
+# Default: ""
+#thread-prefix-lone = ""
+
+#
+# Customize the thread prefix appearance by selecting the connector used if the
+# message has no parents and has children.
+#
+# Default: ""
+#thread-prefix-orphan = ""
+
+#
+# Customize the thread prefix appearance by selecting the connector for the last
+# sibling.
+#
+# Default: "└─"
+#thread-prefix-last-sibling = "└─"
+
+#
+# Customize the reversed thread prefix appearance by selecting the connector for
+# the last sibling.
+#
+# Default: "┌─"
+#thread-prefix-last-sibling-reverse = "┌─"
+
+#
+# Customize the reversed thread prefix appearance by selecting the first child
+# connector.
+#
+# Default: ""
+#thread-prefix-first-child-reverse = ""
+
+#
+# Customize the reversed thread prefix appearance by selecting the connector
+# used if the message has no parents and has children.
+#
+# Default: ""
+#thread-prefix-orphan-reverse = ""
+
[statusline]
#
# Describes the format for the status line. This is a comma separated list of
diff --git a/config/ui.go b/config/ui.go
index 83b45230..9a97d4ef 100644
--- a/config/ui.go
+++ b/config/ui.go
@@ -78,6 +78,21 @@ type UIConfig struct {
ReverseThreadOrder bool `ini:"reverse-thread-order"`
SortThreadSiblings bool `ini:"sort-thread-siblings"`
+ ThreadPrefixTip string `ini:"thread-prefix-tip" default:">"`
+ ThreadPrefixIndent string `ini:"thread-prefix-indent" default:" "`
+ ThreadPrefixStem string `ini:"thread-prefix-stem" default:"│"`
+ ThreadPrefixLimb string `ini:"thread-prefix-limb" default:""`
+ ThreadPrefixFolded string `ini:"thread-prefix-folded" default:""`
+ ThreadPrefixUnfolded string `ini:"thread-prefix-unfolded" default:""`
+ ThreadPrefixFirstChild string `ini:"thread-prefix-first-child" default:""`
+ ThreadPrefixHasSiblings string `ini:"thread-prefix-has-siblings" default:"├─"`
+ ThreadPrefixLone string `ini:"thread-prefix-lone" default:""`
+ ThreadPrefixOrphan string `ini:"thread-prefix-orphan" default:""`
+ ThreadPrefixLastSibling string `ini:"thread-prefix-last-sibling" default:"└─"`
+ ThreadPrefixLastSiblingReverse string `ini:"thread-prefix-last-sibling-reverse" default:"┌─"`
+ ThreadPrefixFirstChildReverse string `ini:"thread-prefix-first-child-reverse" default:""`
+ ThreadPrefixOrphanReverse string `ini:"thread-prefix-orphan-reverse" default:""`
+
// Tab Templates
TabTitleAccount *template.Template `ini:"tab-title-account" default:"{{.Account}}"`
TabTitleComposer *template.Template `ini:"tab-title-composer" default:"{{.Subject}}"`
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 1aa9da5f..9ba7a941 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -469,6 +469,129 @@ These options are configured in the *[ui]* section of _aerc.conf_.
Default: _false_
+## THREAD PREFIX CUSTOMIZATION
+
+You can fully customize the thread arrows appearance, which is defined by the
+following configurable prefix parts:
+
+*thread-prefix-tip* = _<string>_
+ Define the arrow head.
+
+ Default: _">"_
+
+*thread-prefix-indent* = _<string>_
+ Define the arrow indentation.
+
+ Default: _" "_
+
+*thread-prefix-stem* = _<string>_
+ Define the vertical extension of the arrow.
+
+ Default: _"│"_
+
+*thread-prefix-limb* = _<string>_
+ Define the horizontal extension of the arrow.
+
+ Default: _""_
+
+*thread-prefix-folded* = _<string>_
+ Define the folded thread indicator.
+
+ Default: _""_
+
+*thread-prefix-unfolded* = _<string>_
+ Define the unfolded thread indicator.
+
+ Default: _""_
+
+*thread-prefix-first-child* = _<string>_
+ Define the first child connector.
+
+ Default: _""_
+
+*thread-prefix-has-siblings* = _<string>_
+ Define the connector used if the message has siblings.
+
+ Default: _├─_
+
+*thread-prefix-lone* = _<string>_
+ Define the connector used if the message has no parents and no children.
+
+ Default: _""_
+
+*thread-prefix-orphan* = _<string>_
+ Define the connector used if the message has no parents and has children.
+
+ Default: _""_
+
+*thread-prefix-last-sibling* = _<string>_
+ Define the connector for the last sibling.
+
+ Default: _└─_
+
+*thread-prefix-last-sibling-reverse* = _<string>_
+ Define the connector for the last sibling in reversed threads.
+
+ Default: _┌─_
+
+*thread-prefix-first-child-reverse* = _<string>_
+
+ Define the arrow appearance by selecting the first child connector in
+ reversed threads.
+
+ Default: _""_
+
+*thread-prefix-orphan-reverse* = _<string>_
+ Customize the reversed threads arrow appearance by selecting the
+ connector used if the message has no parents and has children.
+
+ Default: _""_
+
+
+Default settings (mutt-style):
+
+ ```
+ [PATCH aerc v5] ui: allow thread arrow customisation
+ ├─>[aerc/patches] build success
+ ├─>Re: [PATCH aerc v5] ui: allow thread arrow customisation
+ ├─
+ └─>
+ ├─>
+ │ ├─>
+ │ └─>
+ │ └─>
+ └─>
+ ```
+
+More compact, rounded threads that are also fold-aware:
+
+ ```
+ ┌[PATCH aerc v5] ui: allow thread arrow customisation
+ ├─[aerc/patches] build success
+ ├─Re: [PATCH aerc v5] ui: allow thread arrow customisation
+ ├+
+ ╰┬
+ ├┬
+ │├─
+ │╰┬
+ │ ╰─
+ ╰─
+ ```
+
+```
+thread-prefix-tip = ""
+thread-prefix-indent = ""
+thread-prefix-stem = "│"
+thread-prefix-limb = "─"
+thread-prefix-folded = "+"
+thread-prefix-unfolded = ""
+thread-prefix-first-child = "┬"
+thread-prefix-has-siblings = "├"
+thread-prefix-orphan = "┌"
+thread-prefix-lone = " "
+thread-prefix-last-sibling = "╰"
+```
+
## CONTEXTUAL UI CONFIGURATION
The UI configuration can be specialized for accounts, specific mail