feat(ags clipboard): hide long clips past 5 lines
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
1928a74e90
commit
59675a6d1f
5 changed files with 137 additions and 66 deletions
|
@ -46,15 +46,17 @@
|
|||
all: unset;
|
||||
transition: 200ms;
|
||||
border-radius: 9px;
|
||||
|
||||
box {
|
||||
padding: 10px;
|
||||
}
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
*:selected .item,
|
||||
.item:hover,
|
||||
.item:focus {
|
||||
*:hover .item,
|
||||
*:focus .item {
|
||||
background-color: #363449;
|
||||
}
|
||||
|
||||
.down-arrow {
|
||||
transition: all 500ms;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,15 +47,17 @@
|
|||
all: unset;
|
||||
transition: 200ms;
|
||||
border-radius: 9px;
|
||||
|
||||
box {
|
||||
padding: 10px;
|
||||
}
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
*:selected .item,
|
||||
.item:hover,
|
||||
.item:focus {
|
||||
*:hover .item,
|
||||
*:focus .item {
|
||||
background-color: #363449;
|
||||
}
|
||||
|
||||
.down-arrow {
|
||||
transition: all 500ms;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class Clipboard extends Service {
|
|||
// Public Class Methods
|
||||
public copyOldItem(key: string | number): void {
|
||||
execAsync([
|
||||
'bash', '-c', `cliphist list | grep ${key} | cliphist decode | wl-copy`,
|
||||
'bash', '-c', `cliphist list | grep '^${key}' | cliphist decode | wl-copy`,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -63,9 +63,28 @@ class Clipboard extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
private _getHistory(n = Clipboard._MAX_CLIPS) {
|
||||
this._clips = new Map();
|
||||
private _addClip(newClip: [number, { clip: string, isImage: boolean }]) {
|
||||
if (
|
||||
![...this.clips.values()]
|
||||
.map((c) => c.clip)
|
||||
.includes(newClip[1].clip)
|
||||
) {
|
||||
this._clips.set(...newClip);
|
||||
this.emit('clip-added', newClip);
|
||||
}
|
||||
else {
|
||||
const oldClip = [...this.clips.entries()]
|
||||
.find(([_, { clip }]) => clip === newClip[1].clip);
|
||||
|
||||
if (oldClip && oldClip[0] < newClip[0]) {
|
||||
this.clips.delete(oldClip[0]);
|
||||
this._clips.set(...newClip);
|
||||
this.emit('clip-added', newClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _getHistory(n = Clipboard._MAX_CLIPS) {
|
||||
// FIXME: this is necessary when not putting a cap on clip amount
|
||||
// exec(`prlimit --pid ${exec('pgrep ags')} --nofile=10024:`);
|
||||
|
||||
|
@ -91,8 +110,7 @@ class Clipboard extends Service {
|
|||
},
|
||||
];
|
||||
|
||||
this._clips.set(...newClip);
|
||||
this.emit('clip-added', newClip);
|
||||
this._addClip(newClip);
|
||||
}
|
||||
else {
|
||||
const decodedClip = await this._decodeItem(clip);
|
||||
|
@ -106,8 +124,7 @@ class Clipboard extends Service {
|
|||
},
|
||||
];
|
||||
|
||||
this._clips.set(...newClip);
|
||||
this.emit('clip-added', newClip);
|
||||
this._addClip(newClip);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
80
modules/ags/config/ts/clipboard/clip.ts
Normal file
80
modules/ags/config/ts/clipboard/clip.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
const { Box, Button, Icon, Label, Revealer } = Widget;
|
||||
|
||||
|
||||
const ImageClip = (key: number, val: string) => Box({
|
||||
class_name: 'item',
|
||||
name: key.toString(),
|
||||
|
||||
child: Icon({
|
||||
icon: val.replace('img:', ''),
|
||||
size: 100 * 2,
|
||||
}),
|
||||
});
|
||||
|
||||
const TextClip = (key: number, val: string) => {
|
||||
const lines = val.split('\n');
|
||||
|
||||
if (lines.length <= 5) {
|
||||
return Box({
|
||||
class_name: 'item',
|
||||
name: key.toString(),
|
||||
|
||||
child: Label({
|
||||
label: val,
|
||||
truncate: 'end',
|
||||
max_width_chars: 100,
|
||||
}),
|
||||
});
|
||||
}
|
||||
else {
|
||||
const revText = Revealer({
|
||||
hpack: 'start',
|
||||
child: Label({
|
||||
label: lines.slice(2, lines.length).join('\n'),
|
||||
truncate: 'end',
|
||||
max_width_chars: 100,
|
||||
}),
|
||||
});
|
||||
|
||||
return Box({
|
||||
class_name: 'item',
|
||||
name: key.toString(),
|
||||
|
||||
vertical: true,
|
||||
children: [
|
||||
Label({
|
||||
label: lines.slice(0, 2).join('\n'),
|
||||
truncate: 'end',
|
||||
max_width_chars: 100,
|
||||
hpack: 'start',
|
||||
}),
|
||||
|
||||
revText,
|
||||
|
||||
Button({
|
||||
child: Icon({
|
||||
class_name: 'down-arrow',
|
||||
icon: 'down-large-symbolic',
|
||||
size: 24,
|
||||
}),
|
||||
|
||||
on_primary_click_release: (self) => {
|
||||
const state = !revText.reveal_child;
|
||||
|
||||
revText.reveal_child = state;
|
||||
|
||||
self.child.setCss(`
|
||||
-gtk-icon-transform: rotate(${state ? '180' : '0'}deg);
|
||||
`);
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default ({
|
||||
key = 0,
|
||||
isImage = false,
|
||||
val = '',
|
||||
}) => isImage ? ImageClip(key, val) : TextClip(key, val);
|
|
@ -1,55 +1,17 @@
|
|||
const { Box, Icon, Label } = Widget;
|
||||
|
||||
import { Fzf, FzfResultItem } from 'fzf';
|
||||
import Gtk from 'gi://Gtk?version=3.0';
|
||||
import Clipboard from '../../services/clipboard.ts';
|
||||
|
||||
import CursorBox from '../misc/cursorbox.ts';
|
||||
import SortedList from '../misc/sorted-list.ts';
|
||||
|
||||
import ClipWidget from './clip.ts';
|
||||
|
||||
|
||||
const getKey = (r: Gtk.ListBoxRow): number => parseInt(r.get_child()?.name ?? '0');
|
||||
|
||||
export default () => {
|
||||
const makeItem = (
|
||||
list: Gtk.ListBox,
|
||||
key: number,
|
||||
val: string,
|
||||
isImage: boolean,
|
||||
): void => {
|
||||
const widget = CursorBox({
|
||||
class_name: 'item',
|
||||
name: key.toString(),
|
||||
|
||||
on_primary_click_release: () => {
|
||||
Clipboard.copyOldItem(key);
|
||||
App.closeWindow('win-clipboard');
|
||||
},
|
||||
|
||||
child: Box({
|
||||
children: [
|
||||
isImage ?
|
||||
Icon({
|
||||
icon: val.replace('img:', ''),
|
||||
size: 100 * 2,
|
||||
}) :
|
||||
|
||||
Label({
|
||||
label: val,
|
||||
truncate: 'end',
|
||||
max_width_chars: 100,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
list.add(widget);
|
||||
widget.show_all();
|
||||
};
|
||||
|
||||
let fzfResults = [] as FzfResultItem<[number, { clip: string, isImage: boolean }]>[];
|
||||
|
||||
const getKey = (r: Gtk.ListBoxRow): number => parseInt(r.get_child()?.name ?? '0');
|
||||
|
||||
|
||||
return SortedList({
|
||||
name: 'clipboard',
|
||||
class_name: 'clipboard',
|
||||
|
@ -61,18 +23,23 @@ export default () => {
|
|||
},
|
||||
|
||||
setup_list: (list, entry) => {
|
||||
list.cursor = 'pointer';
|
||||
|
||||
const CONNECT_ID = Clipboard.connect('history-searched', () => {
|
||||
// Do every clip that existed before this widget
|
||||
list.get_children().forEach((row) => {
|
||||
row.destroy();
|
||||
});
|
||||
Clipboard.clips.forEach((clip, key) => {
|
||||
makeItem(list, key, clip.clip, clip.isImage);
|
||||
const widget = ClipWidget({ key, isImage: clip.isImage, val: clip.clip });
|
||||
|
||||
list.add(widget);
|
||||
widget.show_all();
|
||||
});
|
||||
|
||||
// Setup connection for new clips
|
||||
Clipboard.connect('clip-added', (_, [key, clip]) => {
|
||||
makeItem(list, key, clip.clip, clip.isImage);
|
||||
const widget = ClipWidget({ key, isImage: clip.isImage, val: clip.clip });
|
||||
|
||||
list.add(widget);
|
||||
widget.show_all();
|
||||
});
|
||||
|
||||
list.set_sort_func((a, b) => {
|
||||
|
@ -93,6 +60,9 @@ export default () => {
|
|||
}
|
||||
});
|
||||
|
||||
// Trigger on_text_change after init
|
||||
entry.text = '-';
|
||||
|
||||
Clipboard.disconnect(CONNECT_ID);
|
||||
});
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue