Added the ability to ignore workspaces by number or regex

This commit is contained in:
Jas Singh
2024-09-25 00:49:08 -07:00
parent d60d3db401
commit c01ddce201
6 changed files with 87 additions and 68 deletions

View File

@@ -215,3 +215,6 @@ export type ColorMapKey = keyof typeof defaultColorMap;
export type ColorMapValue = (typeof defaultColorMap)[ColorMapKey]; export type ColorMapValue = (typeof defaultColorMap)[ColorMapKey];
export type ScalingPriority = 'gdk' | 'hyprland' | 'both'; export type ScalingPriority = 'gdk' | 'hyprland' | 'both';
export type IgnoredWorkspace = number | string;
export type IgnoredWorkspaces = IgnoredWorkspace[];

View File

@@ -1,10 +1,11 @@
const hyprland = await Service.import('hyprland'); const hyprland = await Service.import('hyprland');
import { IgnoredWorkspace, IgnoredWorkspaces } from 'lib/types/options';
import { MonitorMap, WorkspaceMap, WorkspaceRule } from 'lib/types/workspace'; import { MonitorMap, WorkspaceMap, WorkspaceRule } from 'lib/types/workspace';
import options from 'options'; import options from 'options';
import { Variable } from 'types/variable'; import { Variable } from 'types/variable';
const { workspaces, reverse_scroll } = options.bar.workspaces; const { workspaces, reverse_scroll, ignored } = options.bar.workspaces;
export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, monitor: number): boolean => { export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, monitor: number): boolean => {
if (!wsRules || !Object.keys(wsRules).length) { if (!wsRules || !Object.keys(wsRules).length) {
@@ -66,63 +67,70 @@ export const getCurrentMonitorWorkspaces = (monitor: number): number[] => {
return monitorWorkspaces[currentMonitorName]; return monitorWorkspaces[currentMonitorName];
}; };
export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => { type ThrottledScrollHandlers = {
if (activeWorkspaces === true) { throttledScrollUp: () => void;
const activeWses = hyprland.workspaces.filter((ws) => hyprland.active.monitor.id === ws.monitorID); throttledScrollDown: () => void;
};
let nextIndex = hyprland.active.workspace.id + 1; export const isWorkspaceIgnored = (
if (nextIndex > activeWses[activeWses.length - 1].id) { ignoredWorkspaces: Variable<IgnoredWorkspaces>,
nextIndex = activeWses[0].id; workspaceNumber: number,
): boolean => {
const ignoredValues = ignoredWorkspaces.value;
return ignoredValues.some((ignore: IgnoredWorkspace) => {
if (typeof ignore === 'number') {
return ignore === workspaceNumber;
} }
if (typeof ignore === 'string') {
hyprland.messageAsync(`dispatch workspace ${nextIndex}`); return new RegExp(ignore).test(workspaceNumber.toString());
} else if (currentMonitorWorkspaces.value === undefined) {
let nextIndex = hyprland.active.workspace.id + 1;
if (nextIndex > workspaces.value) {
nextIndex = 0;
} }
return true;
});
};
hyprland.messageAsync(`dispatch workspace ${nextIndex}`); const navigateWorkspace = (
} else { direction: 'next' | 'prev',
const curWorkspace = hyprland.active.workspace.id; currentMonitorWorkspaces: Variable<number[]>,
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace); activeWorkspaces: boolean,
let nextIndex = indexOfWs + 1; ignoredWorkspaces: Variable<IgnoredWorkspaces>,
if (nextIndex >= currentMonitorWorkspaces.value.length) { ): void => {
nextIndex = 0; const workspacesList = activeWorkspaces
? hyprland.workspaces.filter((ws) => hyprland.active.monitor.id === ws.monitorID).map((ws) => ws.id)
: currentMonitorWorkspaces.value || Array.from({ length: workspaces.value }, (_, i) => i + 1);
if (workspacesList.length === 0) return;
const currentIndex = workspacesList.indexOf(hyprland.active.workspace.id);
const step = direction === 'next' ? 1 : -1;
let newIndex = (currentIndex + step + workspacesList.length) % workspacesList.length;
let attempts = 0;
while (attempts < workspacesList.length) {
const targetWS = workspacesList[newIndex];
if (!isWorkspaceIgnored(ignoredWorkspaces, targetWS)) {
hyprland.messageAsync(`dispatch workspace ${targetWS}`);
return;
} }
newIndex = (newIndex + step + workspacesList.length) % workspacesList.length;
hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[nextIndex]}`); attempts++;
} }
}; };
export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => { export const goToNextWS = (
if (activeWorkspaces === true) { currentMonitorWorkspaces: Variable<number[]>,
const activeWses = hyprland.workspaces.filter((ws) => hyprland.active.monitor.id === ws.monitorID); activeWorkspaces: boolean,
ignoredWorkspaces: Variable<IgnoredWorkspaces>,
): void => {
navigateWorkspace('next', currentMonitorWorkspaces, activeWorkspaces, ignoredWorkspaces);
};
let prevIndex = hyprland.active.workspace.id - 1; export const goToPrevWS = (
if (prevIndex < activeWses[0].id) { currentMonitorWorkspaces: Variable<number[]>,
prevIndex = activeWses[activeWses.length - 1].id; activeWorkspaces: boolean,
} ignoredWorkspaces: Variable<IgnoredWorkspaces>,
): void => {
hyprland.messageAsync(`dispatch workspace ${prevIndex}`); navigateWorkspace('prev', currentMonitorWorkspaces, activeWorkspaces, ignoredWorkspaces);
} else if (currentMonitorWorkspaces.value === undefined) {
let prevIndex = hyprland.active.workspace.id - 1;
if (prevIndex <= 0) {
prevIndex = workspaces.value;
}
hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
} else {
const curWorkspace = hyprland.active.workspace.id;
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
let prevIndex = indexOfWs - 1;
if (prevIndex < 0) {
prevIndex = currentMonitorWorkspaces.value.length - 1;
}
hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[prevIndex]}`);
}
}; };
export function throttle<T extends (...args: unknown[]) => void>(func: T, limit: number): T { export function throttle<T extends (...args: unknown[]) => void>(func: T, limit: number): T {
@@ -138,29 +146,24 @@ export function throttle<T extends (...args: unknown[]) => void>(func: T, limit:
} as T; } as T;
} }
type ThrottledScrollHandlers = {
throttledScrollUp: () => void;
throttledScrollDown: () => void;
};
export const createThrottledScrollHandlers = ( export const createThrottledScrollHandlers = (
scrollSpeed: number, scrollSpeed: number,
currentMonitorWorkspaces: Variable<number[]>, currentMonitorWorkspaces: Variable<number[]>,
activeWorkspaces: boolean = false, activeWorkspaces: boolean = false,
): ThrottledScrollHandlers => { ): ThrottledScrollHandlers => {
const throttledScrollUp = throttle(() => { const throttledScrollUp = throttle(() => {
if (reverse_scroll.value === true) { if (reverse_scroll.value) {
goToPrevWS(currentMonitorWorkspaces, activeWorkspaces); goToPrevWS(currentMonitorWorkspaces, activeWorkspaces, ignored);
} else { } else {
goToNextWS(currentMonitorWorkspaces, activeWorkspaces); goToNextWS(currentMonitorWorkspaces, activeWorkspaces, ignored);
} }
}, 200 / scrollSpeed); }, 200 / scrollSpeed);
const throttledScrollDown = throttle(() => { const throttledScrollDown = throttle(() => {
if (reverse_scroll.value === true) { if (reverse_scroll.value) {
goToNextWS(currentMonitorWorkspaces, activeWorkspaces); goToNextWS(currentMonitorWorkspaces, activeWorkspaces, ignored);
} else { } else {
goToPrevWS(currentMonitorWorkspaces, activeWorkspaces); goToPrevWS(currentMonitorWorkspaces, activeWorkspaces, ignored);
} }
}, 200 / scrollSpeed); }, 200 / scrollSpeed);

View File

@@ -1,24 +1,27 @@
const hyprland = await Service.import('hyprland'); const hyprland = await Service.import('hyprland');
import options from 'options'; import options from 'options';
import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers'; import { getWorkspaceRules, getWorkspacesForMonitor, isWorkspaceIgnored } from '../helpers';
import { range } from 'lib/utils'; import { range } from 'lib/utils';
import { BoxWidget } from 'lib/types/widget'; import { BoxWidget } from 'lib/types/widget';
import { getWsColor, renderClassnames, renderLabel } from '../utils'; import { getWsColor, renderClassnames, renderLabel } from '../utils';
import { WorkspaceIconMap } from 'lib/types/workspace'; import { WorkspaceIconMap } from 'lib/types/workspace';
const { workspaces, monitorSpecific, workspaceMask, spacing } = options.bar.workspaces; const { workspaces, monitorSpecific, workspaceMask, spacing, ignored } = options.bar.workspaces;
export const defaultWses = (monitor: number): BoxWidget => { export const defaultWses = (monitor: number): BoxWidget => {
return Widget.Box({ return Widget.Box({
children: Utils.merge( children: Utils.merge(
[workspaces.bind('value'), monitorSpecific.bind()], [workspaces.bind('value'), monitorSpecific.bind('value'), ignored.bind('value')],
(workspaces: number, monitorSpecific: boolean) => { (workspaces: number, monitorSpecific: boolean) => {
return range(workspaces || 8) return range(workspaces || 8)
.filter((i) => { .filter((workspaceNumber) => {
if (!monitorSpecific) { if (!monitorSpecific) {
return true; return true;
} }
const workspaceRules = getWorkspaceRules(); const workspaceRules = getWorkspaceRules();
return getWorkspacesForMonitor(i, workspaceRules, monitor); return (
getWorkspacesForMonitor(workspaceNumber, workspaceRules, monitor) &&
!isWorkspaceIgnored(ignored, workspaceNumber)
);
}) })
.sort((a, b) => { .sort((a, b) => {
return a - b; return a - b;

View File

@@ -1,13 +1,13 @@
const hyprland = await Service.import('hyprland'); const hyprland = await Service.import('hyprland');
import options from 'options'; import options from 'options';
import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers'; import { getWorkspaceRules, getWorkspacesForMonitor, isWorkspaceIgnored } from '../helpers';
import { Workspace } from 'types/service/hyprland'; import { Workspace } from 'types/service/hyprland';
import { getWsColor, renderClassnames, renderLabel } from '../utils'; import { getWsColor, renderClassnames, renderLabel } from '../utils';
import { range } from 'lib/utils'; import { range } from 'lib/utils';
import { BoxWidget } from 'lib/types/widget'; import { BoxWidget } from 'lib/types/widget';
import { WorkspaceIconMap } from 'lib/types/workspace'; import { WorkspaceIconMap } from 'lib/types/workspace';
const { workspaces, monitorSpecific, workspaceMask, spacing } = options.bar.workspaces; const { workspaces, monitorSpecific, workspaceMask, spacing, ignored } = options.bar.workspaces;
export const occupiedWses = (monitor: number): BoxWidget => { export const occupiedWses = (monitor: number): BoxWidget => {
return Widget.Box({ return Widget.Box({
@@ -28,6 +28,7 @@ export const occupiedWses = (monitor: number): BoxWidget => {
options.bar.workspaces.workspaceIconMap.bind('value'), options.bar.workspaces.workspaceIconMap.bind('value'),
options.bar.workspaces.showWsIcons.bind('value'), options.bar.workspaces.showWsIcons.bind('value'),
options.theme.matugen.bind('value'), options.theme.matugen.bind('value'),
ignored.bind('value'),
], ],
( (
monitorSpecific: boolean, monitorSpecific: boolean,
@@ -61,7 +62,6 @@ export const occupiedWses = (monitor: number): BoxWidget => {
hyprland.monitors.find((m) => m.id === monitor) || hyprland.monitors.find((m) => m.id === monitor) ||
workspaceMonitorList.find((m) => m.id === monitor); workspaceMonitorList.find((m) => m.id === monitor);
// go through each key in workspaceRules and flatten the array
const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => { const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => {
return [...acc, ...workspaceRules[k]]; return [...acc, ...workspaceRules[k]];
}, [] as number[]); }, [] as number[]);
@@ -87,6 +87,9 @@ export const occupiedWses = (monitor: number): BoxWidget => {
} }
return allWkspcs return allWkspcs
.filter((workspaceNumber) => {
return !isWorkspaceIgnored(ignored, workspaceNumber);
})
.sort((a, b) => { .sort((a, b) => {
return a - b; return a - b;
}) })

View File

@@ -13,6 +13,7 @@ import {
ActiveWsIndicator, ActiveWsIndicator,
BarButtonStyles, BarButtonStyles,
BarLocation, BarLocation,
IgnoredWorkspaces,
NotificationAnchor, NotificationAnchor,
OSDAnchor, OSDAnchor,
OSDOrientation, OSDOrientation,
@@ -861,6 +862,7 @@ const options = mkOptions(OPTIONS, {
}, },
workspaces: { workspaces: {
show_icons: opt(false), show_icons: opt(false),
ignored: opt<IgnoredWorkspaces>([]),
show_numbered: opt(false), show_numbered: opt(false),
showWsIcons: opt(false), showWsIcons: opt(false),
numbered_active_indicator: opt<ActiveWsIndicator>('underline'), numbered_active_indicator: opt<ActiveWsIndicator>('underline'),

View File

@@ -297,6 +297,11 @@ export const BarSettings = (): Scrollable<Gtk.Widget, Gtk.Widget> => {
title: 'Scrolling Speed', title: 'Scrolling Speed',
type: 'number', type: 'number',
}), }),
Option({
opt: options.bar.workspaces.ignored,
title: 'Ignored Workspaces',
type: 'object',
}),
/* /*
****************************** ******************************