diff --git a/metainfo.xml b/metainfo.xml
index d3246cac9a..50b03ada8c 100644
--- a/metainfo.xml
+++ b/metainfo.xml
@@ -113,6 +113,7 @@
Adds `MoveTabTo` action to move tabs to a specific position (#1695)
Adds handling of control codes for Ctrl+5|6|7|8 (#1701)
Adds CenterCursor (`zz`) vi motion
+ Adds ability to name tabs (#1690)
diff --git a/src/contour/Config.h b/src/contour/Config.h
index 7447c5e867..36272ba6f5 100644
--- a/src/contour/Config.h
+++ b/src/contour/Config.h
@@ -180,11 +180,10 @@ struct MouseConfig
struct IndicatorConfig
{
std::string left { " {InputMode:Bold,Color=#FFFF00}"
- "{Tabs:ActiveColor=#FFFF00,Left= │ }"
"{SearchPrompt:Left= │ }"
"{TraceMode:Bold,Color=#FFFF00,Left= │ }"
"{ProtectedMode:Bold,Left= │ }" };
- std::string middle { "{Title:Left= « ,Right= » }" };
+ std::string middle { "{Tabs: ActiveColor=#FFFF00}" };
std::string right { "{HistoryLineCount:Faint,Color=#c0c0c0} │ {Clock:Bold}" };
};
diff --git a/src/contour/TerminalSession.cpp b/src/contour/TerminalSession.cpp
index b491048608..0f92dc60ea 100644
--- a/src/contour/TerminalSession.cpp
+++ b/src/contour/TerminalSession.cpp
@@ -149,6 +149,43 @@ namespace
settings.indicatorStatusLine.left = profile.statusLine.value().indicator.left;
settings.indicatorStatusLine.middle = profile.statusLine.value().indicator.middle;
settings.indicatorStatusLine.right = profile.statusLine.value().indicator.right;
+ settings.tabNamingMode = [&]() {
+ // try to find Tab section in one of the status line segments
+
+ std::string segment;
+ if (profile.statusLine.value().indicator.left.find("Tabs") != std::string::npos)
+ {
+ segment = profile.statusLine.value().indicator.left;
+ }
+ else if (profile.statusLine.value().indicator.middle.find("Tabs") != std::string::npos)
+ {
+ segment = profile.statusLine.value().indicator.middle;
+ }
+ else if (profile.statusLine.value().indicator.right.find("Tabs") != std::string::npos)
+ {
+ segment = profile.statusLine.value().indicator.right;
+ }
+
+ // check if indexing is defined
+ if (segment.find("Indexing=") != std::string::npos)
+ {
+ // cut the string after indexing=
+ std::string indexing = segment.substr(segment.find("Indexing=") + 9);
+ // cut right part of the string
+ indexing = indexing.substr(0, indexing.find(','));
+ indexing = indexing.substr(0, indexing.find('}'));
+
+ std::ranges::transform(
+ indexing, indexing.begin(), [](unsigned char c) { return std::tolower(c); });
+
+ if (indexing == "title")
+ {
+ return vtbackend::TabsNamingMode::Title;
+ }
+ }
+ return vtbackend::TabsNamingMode::Indexing;
+ }();
+
settings.syncWindowTitleWithHostWritableStatusDisplay =
profile.statusLine.value().syncWindowTitleWithHostWritableStatusDisplay;
if (auto const* p = preferredColorPalette(profile.colors.value(), colorPreference))
@@ -262,6 +299,7 @@ void TerminalSession::attachDisplay(display::TerminalDisplay& newDisplay)
void TerminalSession::scheduleRedraw()
{
_terminal.markScreenDirty();
+ _manager->Update();
if (_display)
_display->scheduleRedraw();
}
diff --git a/src/contour/TerminalSession.h b/src/contour/TerminalSession.h
index ddc808a5fd..2338072f17 100644
--- a/src/contour/TerminalSession.h
+++ b/src/contour/TerminalSession.h
@@ -220,6 +220,14 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
~TerminalSession() override;
int id() const noexcept { return _id; }
+ std::optional name() const noexcept
+ {
+ if (terminal().tabName())
+ return terminal().tabName();
+ if (terminal().getTabsNamingMode() == vtbackend::TabsNamingMode::Title)
+ return terminal().windowTitle();
+ return std::nullopt;
+ }
/// Starts the VT background thread.
void start();
diff --git a/src/contour/TerminalSessionManager.h b/src/contour/TerminalSessionManager.h
index cfc54b64c0..02a466c1b5 100644
--- a/src/contour/TerminalSessionManager.h
+++ b/src/contour/TerminalSessionManager.h
@@ -27,7 +27,6 @@ class TerminalSessionManager: public QAbstractListModel
TerminalSessionManager(ContourGuiApp& app);
contour::TerminalSession* createSessionInBackground();
- contour::TerminalSession* activateSession(TerminalSession* session, bool isNewSession = false);
Q_INVOKABLE contour::TerminalSession* createSession();
@@ -54,7 +53,10 @@ class TerminalSessionManager: public QAbstractListModel
display::TerminalDisplay* display = nullptr;
TerminalSession* getSession() { return _sessions[0]; }
+ void Update() { updateStatusLine(); }
+
private:
+ contour::TerminalSession* activateSession(TerminalSession* session, bool isNewSession = false);
std::unique_ptr createPty(std::optional cwd);
[[nodiscard]] std::optional getSessionIndexOf(TerminalSession* session) const noexcept
@@ -73,9 +75,15 @@ class TerminalSessionManager: public QAbstractListModel
{
if (!_activeSession)
return;
-
_activeSession->terminal().setGuiTabInfoForStatusLine(vtbackend::TabsInfo {
- .tabCount = _sessions.size(),
+ .tabs = std::ranges::transform_view(_sessions,
+ [](auto* session) {
+ return vtbackend::TabsInfo::Tab {
+ .name = session->name(),
+ .color = vtbackend::RGBColor { 0, 0, 0 },
+ };
+ })
+ | ranges::to(),
.activeTabPosition = 1 + getSessionIndexOf(_activeSession).value_or(0),
});
}
diff --git a/src/vtbackend/Settings.h b/src/vtbackend/Settings.h
index 74be100ea5..1fa4dea995 100644
--- a/src/vtbackend/Settings.h
+++ b/src/vtbackend/Settings.h
@@ -24,6 +24,12 @@ struct RefreshInterval
explicit RefreshInterval(RefreshRate rate): value { static_cast(1000.0 / rate.value) } {}
};
+enum class TabsNamingMode : uint8_t
+{
+ Indexing,
+ Title
+};
+
/// Terminal settings, enabling hardware reset to be easier implemented.
struct Settings
{
@@ -91,6 +97,8 @@ struct Settings
bool fromSearchIntoInsertMode = true;
bool isInsertAfterYank = false;
+ TabsNamingMode tabNamingMode = TabsNamingMode::Indexing;
+
// TODO: we could configure also the number of lines of the host writable statusline and indicator
// statusline.
};
diff --git a/src/vtbackend/StatusLineBuilder.cpp b/src/vtbackend/StatusLineBuilder.cpp
index 2774375421..3dbe605b22 100644
--- a/src/vtbackend/StatusLineBuilder.cpp
+++ b/src/vtbackend/StatusLineBuilder.cpp
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
using namespace std::string_view_literals;
@@ -156,6 +157,7 @@ std::optional makeStatusLineItem(
styles,
activeColor,
activeBackground,
+ std::nullopt, // separator
};
}
@@ -443,10 +445,10 @@ struct VTSerializer
auto const tabsInfo = vt.guiTabsInfoForStatusLine();
std::string fragment;
- for (const auto position: std::views::iota(1u, tabsInfo.tabCount + 1))
+ for (const auto position: std::views::iota(1u, tabsInfo.tabs.size() + 1))
{
if (!fragment.empty())
- fragment += ' ';
+ fragment += tabs.separator.value_or("|");
auto const isActivePosition = position == tabsInfo.activeTabPosition;
auto const activePositionStylized =
@@ -459,7 +461,10 @@ struct VTSerializer
fragment += makeBackgroundColor(tabs.activeBackground);
}
- fragment += std::to_string(position);
+ if (tabsInfo.tabs[position - 1].name)
+ fragment += tabsInfo.tabs[position - 1].name.value();
+ else
+ fragment += std::to_string(position);
if (activePositionStylized)
fragment += SGRRESTORE();
diff --git a/src/vtbackend/StatusLineBuilder.h b/src/vtbackend/StatusLineBuilder.h
index fe64882920..5f6f76d266 100644
--- a/src/vtbackend/StatusLineBuilder.h
+++ b/src/vtbackend/StatusLineBuilder.h
@@ -43,6 +43,7 @@ namespace StatusLineDefinitions
{
std::optional activeColor;
std::optional activeBackground;
+ std::optional separator;
};
using Item = std::variant<
diff --git a/src/vtbackend/Terminal.cpp b/src/vtbackend/Terminal.cpp
index d9fd970c90..3100607759 100644
--- a/src/vtbackend/Terminal.cpp
+++ b/src/vtbackend/Terminal.cpp
@@ -1562,11 +1562,21 @@ void Terminal::setWindowTitle(string_view title)
_eventListener.setWindowTitle(title);
}
+void Terminal::setTabName(string_view title)
+{
+ _tabName = title;
+}
+
std::string const& Terminal::windowTitle() const noexcept
{
return _windowTitle;
}
+std::optional Terminal::tabName() const noexcept
+{
+ return _tabName;
+}
+
void Terminal::saveWindowTitle()
{
_savedWindowTitles.push(_windowTitle);
diff --git a/src/vtbackend/Terminal.h b/src/vtbackend/Terminal.h
index c2676b7b56..dd31ffff90 100644
--- a/src/vtbackend/Terminal.h
+++ b/src/vtbackend/Terminal.h
@@ -42,6 +42,7 @@
#include
#include
#include
+#include
namespace vtbackend
{
@@ -209,7 +210,13 @@ class TraceHandler: public SequenceHandler
struct TabsInfo
{
- size_t tabCount = 1;
+ struct Tab
+ {
+ std::optional name;
+ Color color;
+ };
+
+ std::vector tabs;
size_t activeTabPosition = 1;
};
@@ -246,6 +253,7 @@ class Terminal
virtual void requestWindowResize(Width, Height) {}
virtual void requestShowHostWritableStatusLine() {}
virtual void setWindowTitle(std::string_view /*title*/) {}
+ virtual void setTabName(std::string_view /*title*/) {}
virtual void setTerminalProfile(std::string const& /*configProfileName*/) {}
virtual void discardImage(Image const&) {}
virtual void inputModeChanged(ViMode /*mode*/) {}
@@ -276,6 +284,7 @@ class Terminal
void requestWindowResize(Width, Height) override {}
void requestShowHostWritableStatusLine() override {}
void setWindowTitle(std::string_view /*title*/) override {}
+ void setTabName(std::string_view /*title*/) override {}
void setTerminalProfile(std::string const& /*configProfileName*/) override {}
void discardImage(Image const&) override {}
void inputModeChanged(ViMode /*mode*/) override {}
@@ -797,7 +806,9 @@ class Terminal
void setMouseTransport(MouseTransport transport);
void setMouseWheelMode(InputGenerator::MouseWheelMode mode);
void setWindowTitle(std::string_view title);
+ void setTabName(std::string_view title);
[[nodiscard]] std::string const& windowTitle() const noexcept;
+ [[nodiscard]] std::optional tabName() const noexcept;
[[nodiscard]] bool focused() const noexcept { return _focused; }
[[nodiscard]] Search& search() noexcept { return _search; }
[[nodiscard]] Search const& search() const noexcept { return _search; }
@@ -966,7 +977,9 @@ class Terminal
void resetStatusLineDefinition();
TabsInfo guiTabsInfoForStatusLine() const noexcept { return _guiTabInfoForStatusLine; }
- void setGuiTabInfoForStatusLine(TabsInfo info) { _guiTabInfoForStatusLine = info; }
+ void setGuiTabInfoForStatusLine(TabsInfo&& info) { _guiTabInfoForStatusLine = std::move(info); }
+
+ TabsNamingMode getTabsNamingMode() const noexcept { return _settings.tabNamingMode; }
private:
void mainLoop();
@@ -1080,7 +1093,9 @@ class Terminal
Viewport _viewport;
StatusLineDefinition _indicatorStatusLineDefinition;
+ // {{{ tabs info
TabsInfo _guiTabInfoForStatusLine;
+ // }}}
// {{{ selection states
std::unique_ptr _selection;
@@ -1165,6 +1180,8 @@ class Terminal
std::string _windowTitle {};
std::stack _savedWindowTitles {};
+ std::optional _tabName {};
+
struct ModeDependantSequenceHandler
{
Terminal& terminal;