Skip to content
Merged
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
10 changes: 5 additions & 5 deletions .bash_aliases
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,19 @@ command grep -Fiq microsoft /proc/version && . $HOME/.bash_aliases_wsl.bash
# executed.
_before_command()
{
[ -n "${__begin_window+.}" ] && return
__begin_window=$(custom-bash-prompt)
[ -n "${__begin_ts+.}" ] && return
__begin_ts=$(custom-bash-prompt)
}

# Post-command for command timing. It will be called just before the prompt is
# displayed (i.e. just after any command is executed).
_after_command()
{
local exit_code=$?
[ -z "${__begin_window+.}" ] && return
[ -z "${__begin_ts+.}" ] && return
local last_command=$(history 1)
PS1=$(custom-bash-prompt "$last_command" $exit_code $__begin_window $COLUMNS "$PWD" $SHLVL)
unset __begin_window
PS1=$(custom-bash-prompt "$last_command" $exit_code $__begin_ts $COLUMNS "$PWD" $SHLVL)
unset __begin_ts
}

trap _before_command DEBUG
Expand Down
10 changes: 5 additions & 5 deletions .zshrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
_after_command()
{
local exit_code=$?
[ -z "${__begin_window+.}" ] && return
[ -z "${__begin_ts+.}" ] && return
local last_command=$(history -n -1 2>/dev/null)
PS1=$(custom-zsh-prompt "$last_command" $exit_code $=__begin_window $COLUMNS $PWD $SHLVL)
unset __begin_window
PS1=$(custom-zsh-prompt "$last_command" $exit_code $__begin_ts $COLUMNS $PWD $SHLVL)
unset __begin_ts
}

_before_command()
{
[ -n "${__begin_window+.}" ] && return
__begin_window=$(custom-zsh-prompt)
[ -n "${__begin_ts+.}" ] && return
__begin_ts=$(custom-zsh-prompt)
}

cfs()
Expand Down
20 changes: 6 additions & 14 deletions custom-prompt/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
CC = gcc
CPPFLAGS = $(shell pkg-config --cflags libgit2)
CFLAGS = -fstrict-aliasing -std=c11 -Wall -Wextra -Wno-unused-parameter
CXXFLAGS = -fstrict-aliasing -std=c++17 -Wall -Wextra -Wno-unused-parameter
LDLIBS = -lstdc++ $(shell pkg-config --libs libgit2)

Expand All @@ -9,25 +7,19 @@ MainBashObject = custom-bash-prompt.o
MainBashExecutable = bin/$(MainBashObject:.o=)
MainZshObject = custom-zsh-prompt.o
MainZshExecutable = bin/$(MainZshObject:.o=)
OtherObjects = get_active_wid_linux.o get_active_wid_windows.o json_logger.o

ifneq "$(OS)" "Windows_NT"
UNAME = $(shell uname)
ifeq "$(UNAME)" "Linux"
CPPFLAGS += $(shell pkg-config --cflags glib-2.0 libnotify x11)
LDLIBS += $(shell pkg-config --libs glib-2.0 libnotify x11)
else
LDLIBS += -framework Cocoa -framework CoreGraphics
OtherObjects += get_active_wid_macos.o
endif
OtherObjects = focus_utils.o json_logger.o

UNAME = $(shell uname)
ifeq "$(UNAME)" "Linux"
CPPFLAGS += $(shell pkg-config --cflags libnotify)
LDLIBS += $(shell pkg-config --libs libnotify)
endif

.PHONY: debug release

debug: $(MainBashExecutable) $(MainZshExecutable)

release: CPPFLAGS += -DNDEBUG
release: CFLAGS += -flto -O2
release: CXXFLAGS += -flto -O2
release: LDFLAGS += -flto -O2
release: debug
Expand Down
34 changes: 15 additions & 19 deletions custom-prompt/custom-prompt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <thread>
#include <utility>

#include "get_active_wid.hh"
#include "focus_utils.hh"
#include "json_logger.hh"

namespace C
Expand Down Expand Up @@ -550,8 +550,10 @@ void notify_desktop(std::string_view const& last_command, int exit_code, Interva
#else
// Xfce Terminal (the best terminal) does not support OSC 777. Do it the
// hard way.
C::notify_init(__FILE__);
C::NotifyNotification* notif = C::notify_notification_new(last_command.data(), description.data(), "terminal");
C::notify_init("Terminal");
C::NotifyNotification* notif = C::notify_notification_new(
last_command.data(), description.data(), exit_code == 0 ? "dialog-information" : "dialog-error"
);
C::notify_notification_show(notif, nullptr);
// C::notify_uninit();
#endif
Expand Down Expand Up @@ -630,12 +632,10 @@ void write_report(std::string_view const& last_command, int exit_code, Interval
* @param last_command Most-recently run command.
* @param exit_code Code with which the command exited.
* @param delay Running time of the command in nanoseconds.
* @param prev_active_wid ID of the focused window when the command started.
* @param columns Width of the terminal window.
*/
void report_command_status(
std::string_view& last_command, int exit_code, long long unsigned delay, long long unsigned prev_active_wid,
std::size_t columns
std::string_view& last_command, int exit_code, long long unsigned delay, std::size_t columns
)
{
LOG_DEBUG(
Expand All @@ -662,12 +662,9 @@ void report_command_status(
{
return;
}

long long unsigned curr_active_wid = get_active_wid();
LOG_DEBUG(
logger, "Obtained focused window details", { { "previous", prev_active_wid }, { "current", curr_active_wid } }
);
if (prev_active_wid != curr_active_wid)
bool terminal_focused = terminal_has_focus();
LOG_DEBUG(logger, "Obtained focus details", { { "terminal_focused", terminal_focused } });
if (!terminal_focused)
{
notify_desktop(last_command, exit_code, interval);
}
Expand Down Expand Up @@ -759,7 +756,7 @@ int main_internal(int const argc, char const* argv[])
long long unsigned ts = get_timestamp();
if (argc <= 1)
{
std::cout << ts << ' ' << get_active_wid() << '\n';
std::cout << ts << '\n';
return EXIT_SUCCESS;
}

Expand All @@ -781,12 +778,11 @@ int main_internal(int const argc, char const* argv[])
std::string_view last_command(argv[1]);
int exit_code = std::stoi(argv[2]);
long long unsigned delay = ts - std::stoull(argv[3]);
long long unsigned prev_active_wid = std::stoull(argv[4]);
std::size_t columns = std::stoull(argv[5]);
report_command_status(last_command, exit_code, delay, prev_active_wid, columns);
std::size_t columns = std::stoull(argv[4]);
report_command_status(last_command, exit_code, delay, columns);

std::string_view pwd(argv[6]);
int shlvl = std::stoi(argv[7]);
std::string_view pwd(argv[5]);
int shlvl = std::stoi(argv[6]);
std::string_view venv_view;
char const* venv;
if ((venv = getenv("VIRTUAL_ENV_PROMPT")) != nullptr)
Expand Down Expand Up @@ -814,7 +810,7 @@ int main(int const argc, char const* argv[])
// null-terminated.
if (argc == 2)
{
char const* argv[] = { "custom-prompt", "[] last_command", "0", "0", "0", "79", "/", "1", nullptr };
char const* argv[] = { "custom-prompt", "[] last_command", "0", "0", "79", "/", "1", nullptr };
int constexpr argc = sizeof argv / sizeof *argv - 1;
return main_internal(argc, argv);
}
Expand Down
114 changes: 114 additions & 0 deletions custom-prompt/focus_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "focus_utils.hh"
#include "json_logger.hh"

static JSONLogger logger;

#ifdef _WIN32

#include <tchar.h>
#include <windows.h>

bool terminal_has_focus(void)
{
HWND foreground_window = GetForegroundWindow();
TCHAR class_name[64];
int class_name_len = GetClassName(foreground_window, class_name, sizeof class_name / sizeof *class_name);
LOG_DEBUG(logger, "Read active window", { { "class_name_len", class_name_len } });
if (class_name_len == 0)
{
return false;
}
// I use WezTerm on Windows because it supports OSC 777; I never open more
// than one window. Hence, checking whether a Wezterm window is active is
// sufficient for me.
return _tcscmp(class_name, _T("org.wezfurlong.wezterm")) == 0;
}

#else

#include <iostream>
#include <string_view>

#include <stddef.h>
#include <termios.h>
#include <unistd.h>

#define BUFSIZE 255

/**
* Temporarily modify standard input to allow non-blocking reads.
*/
class NonBlockingStandardInputGuard
{
private:
bool error_occurred;
termios prev_termios, curr_termios;

public:
NonBlockingStandardInputGuard(void);
~NonBlockingStandardInputGuard();
};

/**
* Enable non-canonical mode.
*/
NonBlockingStandardInputGuard::NonBlockingStandardInputGuard(void) : error_occurred(false)
{
if (tcgetattr(STDIN_FILENO, &this->prev_termios) == -1)
{
this->error_occurred = true;
return;
}
this->curr_termios = this->prev_termios;
this->curr_termios.c_lflag &= ~(ECHO | ICANON);
// Block until sufficiently many bytes are available from standard input.
this->curr_termios.c_cc[VMIN] = BUFSIZE;
// But not for too long.
this->curr_termios.c_cc[VTIME] = 1;
if (tcsetattr(STDIN_FILENO, TCSANOW, &this->curr_termios) == -1)
{
this->error_occurred = true;
}
}

/**
* Disable non-canonical mode.
*/
NonBlockingStandardInputGuard::~NonBlockingStandardInputGuard()
{
if (!this->error_occurred)
{
tcsetattr(STDIN_FILENO, TCSANOW, &this->prev_termios);
}
}

bool terminal_has_focus(void)
{
char buf[BUFSIZE];
ssize_t count;
{
NonBlockingStandardInputGuard _;
// Enable and immediately disable focus reporting.
std::clog << "\x1b\x5b?1004h\x1b\x5b?1004l";
count = read(STDIN_FILENO, buf, sizeof buf / sizeof *buf);
}
LOG_DEBUG(logger, "Read non-blocking standard input", { { "count", count } });
if (count <= 0)
{
return false;
}
std::string_view buf_view(buf, count);
size_t focus_out_seq_pos = buf_view.rfind("\x1b\x5bO");
if (focus_out_seq_pos == std::string_view::npos)
{
return true;
}
size_t focus_in_seq_pos = buf_view.rfind("\x1b\x5bI");
if (focus_in_seq_pos == std::string_view::npos)
{
return false;
}
return focus_out_seq_pos < focus_in_seq_pos;
}

#endif
11 changes: 11 additions & 0 deletions custom-prompt/focus_utils.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef FOCUS_UTILS_HH_
#define FOCUS_UTILS_HH_

/**
* Check whether the terminal has GUI focus.
*
* @return Focus state.
*/
bool terminal_has_focus(void);

#endif
25 changes: 0 additions & 25 deletions custom-prompt/get_active_wid.hh

This file was deleted.

31 changes: 0 additions & 31 deletions custom-prompt/get_active_wid_linux.cc

This file was deleted.

19 changes: 0 additions & 19 deletions custom-prompt/get_active_wid_macos.m

This file was deleted.

8 changes: 0 additions & 8 deletions custom-prompt/get_active_wid_windows.cc

This file was deleted.

Loading