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

Allow naming of the tabs #1705

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
<li>Adds `MoveTabTo` action to move tabs to a specific position (#1695)</li>
<li>Adds handling of control codes for Ctrl+5|6|7|8 (#1701)</li>
<li>Adds CenterCursor (`zz`) vi motion</li>
<li>Adds ability to name tabs (#1690)</li>
</ul>
</description>
</release>
Expand Down
1 change: 1 addition & 0 deletions src/contour/Actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ optional<Action> fromString(string const& name)
mapAction<actions::SwitchToPreviousTab>("SwitchToPreviousTab"),
mapAction<actions::SwitchToTabLeft>("SwitchToTabLeft"),
mapAction<actions::SwitchToTabRight>("SwitchToTabRight"),
mapAction<actions::SetTabName>("SetTabName"),
};

auto const lowerCaseName = toLower(name);
Expand Down
8 changes: 7 additions & 1 deletion src/contour/Actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct SwitchToTab{ int position; };
struct SwitchToPreviousTab{};
struct SwitchToTabLeft{};
struct SwitchToTabRight{};
struct SetTabName{};
// clang-format on

using Action = std::variant<CancelSelection,
Expand Down Expand Up @@ -149,7 +150,8 @@ using Action = std::variant<CancelSelection,
SwitchToTab,
SwitchToPreviousTab,
SwitchToTabLeft,
SwitchToTabRight>;
SwitchToTabRight,
SetTabName>;

std::optional<Action> fromString(std::string const& name);

Expand Down Expand Up @@ -276,6 +278,7 @@ namespace documentation
constexpr inline std::string_view SwitchToPreviousTab { "Switch to the previously focused tab" };
constexpr inline std::string_view SwitchToTabLeft { "Switch to tab to the left" };
constexpr inline std::string_view SwitchToTabRight { "Switch to tab to the right" };
constexpr inline std::string_view SetTabName { "Set the name of the current tab" };
} // namespace documentation

inline auto getDocumentation()
Expand Down Expand Up @@ -341,6 +344,7 @@ inline auto getDocumentation()
std::tuple { Action { SwitchToPreviousTab {} }, documentation::SwitchToPreviousTab },
std::tuple { Action { SwitchToTabLeft {} }, documentation::SwitchToTabLeft },
std::tuple { Action { SwitchToTabRight {} }, documentation::SwitchToTabRight },
std::tuple { Action { SetTabName {} }, documentation::SetTabName },
};
}

Expand Down Expand Up @@ -416,6 +420,7 @@ DECLARE_ACTION_FMT(MoveTabToRight)
DECLARE_ACTION_FMT(SwitchToPreviousTab)
DECLARE_ACTION_FMT(SwitchToTabLeft)
DECLARE_ACTION_FMT(SwitchToTabRight)
DECLARE_ACTION_FMT(SetTabName)
// }}}
#undef DECLARE_ACTION_FMT

Expand Down Expand Up @@ -506,6 +511,7 @@ struct std::formatter<contour::actions::Action>: std::formatter<std::string>
HANDLE_ACTION(SwitchToPreviousTab);
HANDLE_ACTION(SwitchToTabLeft);
HANDLE_ACTION(SwitchToTabRight);
HANDLE_ACTION(SetTabName);
if (std::holds_alternative<contour::actions::MoveTabTo>(_action))
{
const auto action = std::get<contour::actions::MoveTabTo>(_action);
Expand Down
3 changes: 1 addition & 2 deletions src/contour/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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}" };
};

Expand Down
2 changes: 2 additions & 0 deletions src/contour/ConfigDocumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,8 @@ constexpr StringLiteral InputMappingsConfig {
"p.\n"
"{comment} - WriteScreen Writes VT sequence in `chars` member to the screen (bypassing the "
"application).\n"
"{comment} - SetTabName Ask the user to assign a name to the active tab.\n"
"\n"
"input_mapping:\n"
};

Expand Down
44 changes: 44 additions & 0 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -262,6 +299,7 @@ void TerminalSession::attachDisplay(display::TerminalDisplay& newDisplay)
void TerminalSession::scheduleRedraw()
{
_terminal.markScreenDirty();
_manager->update();
if (_display)
_display->scheduleRedraw();
}
Expand Down Expand Up @@ -1488,6 +1526,12 @@ bool TerminalSession::operator()(actions::SwitchToTabRight)
return true;
}

bool TerminalSession::operator()(actions::SetTabName)
{
terminal().requestTabName();
return true;
}

// }}}
// {{{ implementation helpers
void TerminalSession::setDefaultCursor()
Expand Down
9 changes: 9 additions & 0 deletions src/contour/TerminalSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
~TerminalSession() override;

int id() const noexcept { return _id; }
std::optional<std::string> 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();
Expand Down Expand Up @@ -364,6 +372,7 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
bool operator()(actions::SwitchToPreviousTab);
bool operator()(actions::SwitchToTabLeft);
bool operator()(actions::SwitchToTabRight);
bool operator()(actions::SetTabName);

void scheduleRedraw();

Expand Down
14 changes: 11 additions & 3 deletions src/contour/TerminalSessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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<vtpty::Pty> createPty(std::optional<std::string> cwd);

[[nodiscard]] std::optional<std::size_t> getSessionIndexOf(TerminalSession* session) const noexcept
Expand All @@ -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<std::vector>(),
.activeTabPosition = 1 + getSessionIndexOf(_activeSession).value_or(0),
});
}
Expand Down
8 changes: 8 additions & 0 deletions src/vtbackend/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ struct RefreshInterval
explicit RefreshInterval(RefreshRate rate): value { static_cast<long long>(1000.0 / rate.value) } {}
};

enum class TabsNamingMode : uint8_t
{
Indexing,
Title
};

/// Terminal settings, enabling hardware reset to be easier implemented.
struct Settings
{
Expand Down Expand Up @@ -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.
};
Expand Down
14 changes: 11 additions & 3 deletions src/vtbackend/StatusLineBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <chrono>
#include <cstdio>
#include <format>
#include <optional>

using namespace std::string_view_literals;

Expand Down Expand Up @@ -156,6 +157,7 @@ std::optional<StatusLineDefinitions::Item> makeStatusLineItem(
styles,
activeColor,
activeBackground,
std::nullopt, // separator
};
}

Expand Down Expand Up @@ -404,6 +406,9 @@ struct VTSerializer
return std::format("Search: {}█",
unicode::convert_to<char>(std::u32string_view(vt.search().pattern)));

if (vt.inputHandler().isEditingPrompt())
return std::format("{}{}█", vt.prompt().prompt, vt.prompt().text);

return {};
}

Expand Down Expand Up @@ -443,10 +448,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 =
Expand All @@ -459,7 +464,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();
Expand Down
1 change: 1 addition & 0 deletions src/vtbackend/StatusLineBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace StatusLineDefinitions
{
std::optional<RGBColor> activeColor;
std::optional<RGBColor> activeBackground;
std::optional<std::string> separator;
};

using Item = std::variant<
Expand Down
20 changes: 20 additions & 0 deletions src/vtbackend/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,16 @@ std::string const& Terminal::windowTitle() const noexcept
return _windowTitle;
}

void Terminal::requestTabName()
{
inputHandler().setTabName([&](std::string name) { _tabName = std::move(name); });
}

std::optional<std::string> Terminal::tabName() const noexcept
{
return _tabName;
}

void Terminal::saveWindowTitle()
{
_savedWindowTitles.push(_windowTitle);
Expand Down Expand Up @@ -2195,6 +2205,16 @@ bool Terminal::setNewSearchTerm(std::u32string text, bool initiatedByDoubleClick
return true;
}

void Terminal::setPrompt(std::string prompt)
{
_prompt.prompt = std::move(prompt);
}

void Terminal::setPromptText(std::string text)
{
_prompt.text = std::move(text);
}

optional<CellLocation> Terminal::searchReverse(u32string text, CellLocation searchPosition)
{
if (!setNewSearchTerm(std::move(text), false))
Expand Down
Loading
Loading