import ../../globurrl import std/[strutils,os,db_sqlite,osproc] const CLIP_DB = WM_TOOLS_DIR & "clipurr_cache.sqlite" const KEEP_ITEMS = 15 proc openDBConn(): DBConn proc addClip(str: var string) proc killOldRunningProcesses() = let x = execCmdEx("killall wl-paste clipnotify") echo x proc runDaemon() = echo "Starting Daemon..." if wayland: echo "Using Wl-paste" let cwd = getAppDir() let outp = execProcess("wl-paste -n -w " & cwd & "/clipurr set") else: var run = true while run: # TODO; # Check if WM is running otherwise the TTY will be spammed with "Using Clipnotify" text echo "Using Clipnotify" let outp = execCmdEx("clipnotify") if outp.exitcode == 0: var content = getCurrentClipboardContent() addClip(content) echo "Exiting Daemon..." proc openDBConn(): DBConn = let db: DBconn = open(CLIP_DB,"","","") try: db.exec(sql"""create table if not exists clip_items ( timestamp DATETIME NOT NULL, clip NVARCHAR(500) NOT NULL ) """) except: echo getCurrentExceptionMsg() return db proc clearHistory() = let db = openDBConn() try: db.exec(sql"drop table if exists clip_items") except: echo getCurrentExceptionMsg() proc maintainDB() = return # order by and offset doesn't work unless certain sqlite compile time options set # will create a different way to do this try: let db = openDBConn() defer: db.close() db.exec(sql"""BEGIN""") db.exec(sql"delete from clip_items order by timestamp desc offset ?", KEEP_ITEMS) db.exec(sql"""COMMIT""") except: echo "Error cleaning DB : " & getCurrentExceptionMsg() proc escapeClip(str: string): string = var clip = str clip = clip.replace("`","\\`") clip = clip.replace("\\n`","\\\\n`") clip = clip.replace("\x0A","\\x0A") clip = escape(clip) echo "CLIP : ", clip return strip(clip) proc unescapeClip(str: string): string = var clip = str try: clip = unescape(clip) if contains(clip,"\\x0A"): echo "NEWLINE FOUND" let idx = find(clip, "\\x0A") - 1 clip = clip[0 .. idx] & " ... more ..." except: echo getCurrentExceptionMsg() return strip(clip) proc readClipFile(): seq[string] = var clips: seq[string] = @[] # let db = openDBConn() try: let db = openDBConn() defer: db.close() for row in db.fastRows(sql"select distinct(clip) from clip_items order by timestamp desc LIMIT ?", KEEP_ITEMS): var str = unescapeClip(row[0]) clips.add(str) except: echo "Error Reading Clip File : " & getCurrentExceptionMsg() return clips proc addClip(str: var string) = if str == "": return elif str[0] == '\x89': var t = str[1..3] echo "Is a ", $t, " file , not storing" str = "[" & t & " Image] (not stored)" try: str = escapeClip(str) echo "clipboard content : ", str let db = openDBConn() defer: db.close() db.exec(sql"""BEGIN""") db.exec(sql"""insert into clip_items (timestamp, clip) values (CURRENT_TIMESTAMP, ?) """, str) db.exec(sql"""COMMIT""") except: echo getCurrentExceptionMsg() return proc getFullClipboardContent(str: string): string = var full = "" try: let db = openDBConn() defer: db.close() let text = "\"" & replace(str," ... more ...", "%") & "\"" let stmt = """ select clip from clip_items where clip like ? order by timestamp desc LIMIT 1""" var prep = db.prepare(stmt) prep.bindParams(text) let res = db.getAllRows(prep) for r in res: # may need to switch to a getRow or getValue method here as this is messy full = unescape(r[0]) full = replace(full, "\\x0A","\x0A") break finalize(prep) except: echo "Error Reading Clip File : " & getCurrentExceptionMsg() return full proc showClips() = let clips = readClipFile() let info = newInfo("Clipurr") let option = outputData(info, clips) if option != "": if contains(option, "... more ..."): let full = getFullClipboardContent(option) copyToClipboard(full) else: copyToClipboard(option) return proc main() = for idx, arg in args: if arg == "daemon": killOldRunningProcesses() runDaemon() return if arg == "set": var content = getCurrentClipboardContent() addClip(content) return if arg == "clear": clearHistory() return showClips() return block start: if isMainModule: main() maintainDB()