diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index 6720a15..c0e9260 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -99,6 +99,14 @@ vim.keymap.set("i", "jj", "", { desc = "Exit insert mode", silent = true }) -- Keybinds to make split navigation easier. -- Use CTRL+ to switch between windows +-- Vertical navigation +vim.keymap.set("n", "", "10j", { desc = "Jump ten spaces down", silent = true }) +vim.keymap.set("n", "", "10k", { desc = "Jump ten spaces up", silent = true }) + +-- Horizontal navigation +vim.keymap.set("n", "", "^", { desc = "Jump to start of line", silent = true }) +vim.keymap.set("n", "", "$", { desc = "Jump to end of line", silent = true }) + -- Telescope vim.keymap.set("n", "ff", ":Telescope find_files", { desc = "Find Files", silent = true }) @@ -210,6 +218,35 @@ vim.opt.rtp:prepend(lazypath) -- PLUGINS require("lazy").setup({ + { + "arminveres/md-pdf.nvim", + branch = "main", -- you can assume that main is somewhat stable until releases will be made + lazy = true, + keys = { + { + ",", + function() + require("md-pdf").convert_md_to_pdf() + end, + desc = "Markdown preview", + }, + }, + opts = {}, + }, + { + "MeanderingProgrammer/render-markdown.nvim", + opts = {}, + dependencies = { "nvim-treesitter/nvim-treesitter", "echasnovski/mini.nvim" }, -- if you use the mini.nvim suite + -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.icons' }, -- if you use standalone mini plugins + -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons + }, + { + "tadmccorkle/markdown.nvim", + ft = "markdown", -- or 'event = "VeryLazy"' + opts = { + -- configuration here or empty for defaults + }, + }, { "OmniSharp/omnisharp-vim", init = function() @@ -736,9 +773,9 @@ require("lazy").setup({ mapping = cmp.mapping.preset.insert({ -- Select the [n]ext item - [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.select_next_item(), -- Select the [p]revious item - [""] = cmp.mapping.select_prev_item(), + [""] = cmp.mapping.select_prev_item(), -- Scroll the documentation window [b]ack / [f]orward [""] = cmp.mapping.scroll_docs(-4), diff --git a/nvim/.config/nvim/lazy-lock.json b/nvim/.config/nvim/lazy-lock.json index eaf8c81..6fcd6af 100644 --- a/nvim/.config/nvim/lazy-lock.json +++ b/nvim/.config/nvim/lazy-lock.json @@ -1,45 +1,47 @@ { - "LuaSnip": { "branch": "master", "commit": "7ad2eaeaca56d6ed63acacbfc114b99f1f67b982" }, + "LuaSnip": { "branch": "master", "commit": "45db5addf8d0a201e1cf247cae4cdce605ad3768" }, "auto-session": { "branch": "main", "commit": "aa01054d478c6d3efc0188cb2ed4850e9f475664" }, "barbar.nvim": { "branch": "master", "commit": "53b5a2f34b68875898f0531032fbf090e3952ad7" }, "biscuit": { "branch": "main", "commit": "4089be2d6051c41558db55bbcc227c9d0c33bb0f" }, "cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" }, "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, "cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" }, - "coc.nvim": { "branch": "master", "commit": "f3406e06421eae672f1e990d8ac5a8b32b3190b9" }, - "conform.nvim": { "branch": "master", "commit": "62eba813b7501b39612146cbf29cd07f1d4ac29c" }, + "conform.nvim": { "branch": "master", "commit": "0ebe875d9c306f5fc829db38492ffff2a70d8e9d" }, "fidget.nvim": { "branch": "main", "commit": "d855eed8a06531a7e8fd0684889b2943f373c469" }, - "gitsigns.nvim": { "branch": "main", "commit": "562dc47189ad3c8696dbf460d38603a74d544849" }, + "gitsigns.nvim": { "branch": "main", "commit": "1ef74b546732f185d0f806860fa5404df7614f28" }, "gruvbox-baby": { "branch": "main", "commit": "bd52e62d8134647090108189e69c8b3cd18bdbbf" }, - "kanagawa.nvim": { "branch": "master", "commit": "e5f7b8a804360f0a48e40d0083a97193ee4fcc87" }, + "kanagawa.nvim": { "branch": "master", "commit": "f491b0fe68fffbece7030181073dfe51f45cda81" }, "lazy.nvim": { "branch": "main", "commit": "077102c5bfc578693f12377846d427f49bc50076" }, "lazydev.nvim": { "branch": "main", "commit": "491452cf1ca6f029e90ad0d0368848fac717c6d2" }, - "love2d.nvim": { "branch": "main", "commit": "9e3927836391a6147247411802917e2da6844042" }, + "love2d.nvim": { "branch": "main", "commit": "b151657fbea8c37e734d68916215262e76dcabf2" }, "lualine.nvim": { "branch": "master", "commit": "b431d228b7bbcdaea818bdc3e25b8cdbe861f056" }, "luvit-meta": { "branch": "main", "commit": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60" }, + "markdown.nvim": { "branch": "master", "commit": "dfa0d2def6dbf77e9206b16dc90cad4dd23d55d2" }, "mason-lspconfig.nvim": { "branch": "main", "commit": "482350b050bd413931c2cdd4857443c3da7d57cb" }, "mason-tool-installer.nvim": { "branch": "main", "commit": "c5e07b8ff54187716334d585db34282e46fa2932" }, "mason.nvim": { "branch": "main", "commit": "e2f7f9044ec30067bc11800a9e266664b88cda22" }, - "mini.nvim": { "branch": "main", "commit": "0bd6c4d25f2b0cc1ecb8b1a0f659cce54627e218" }, - "neovim": { "branch": "main", "commit": "256d086c218a282ae5de79d2c091b1e592a65367" }, + "md-pdf.nvim": { "branch": "main", "commit": "0da0bf9a6e85855762c68b40019851a75543d82b" }, + "mini.nvim": { "branch": "main", "commit": "8413efde2546be4dec9ea424bc6af346a14dffbe" }, + "neovim": { "branch": "main", "commit": "8b1fd252255a7f2c41b4192a787ab62660b29f72" }, "nvim": { "branch": "main", "commit": "4fd72a9ab64b393c2c22b168508fd244877fec96" }, - "nvim-autopairs": { "branch": "master", "commit": "19606af7c039271d5aa96bceff101e7523af3136" }, + "nvim-autopairs": { "branch": "master", "commit": "fd2badc24e675f947162a16c124d395bde80dbd6" }, "nvim-cmp": { "branch": "main", "commit": "ae644feb7b67bf1ce4260c231d1d4300b19c6f30" }, - "nvim-lspconfig": { "branch": "master", "commit": "911167921d49cd5c1c9b2436031d0da3945e787f" }, + "nvim-lspconfig": { "branch": "master", "commit": "bdbc65aadc708ce528efb22bca5f82a7cca6b54d" }, "nvim-numbertoggle": { "branch": "main", "commit": "c5827153f8a955886f1b38eaea6998c067d2992f" }, "nvim-tree.lua": { "branch": "master", "commit": "ad0b95dee55955817af635fa121f6e2486b10583" }, - "nvim-treesitter": { "branch": "master", "commit": "04401b5dd17c3419dae5141677bd256f52d54733" }, - "nvim-web-devicons": { "branch": "master", "commit": "3722e3d1fb5fe1896a104eb489e8f8651260b520" }, + "nvim-treesitter": { "branch": "master", "commit": "4770d9a1a77b0cc2b723c646c3dbe43a9133e5db" }, + "nvim-web-devicons": { "branch": "master", "commit": "9793801f974bba70e4ac5d7eae6c4f5659993d8e" }, "omnisharp-vim": { "branch": "master", "commit": "f9c5d3e3375e8b5688a4506e813cb21bdc7329b1" }, "plenary.nvim": { "branch": "master", "commit": "ec289423a1693aeae6cd0d503bac2856af74edaa" }, + "render-markdown.nvim": { "branch": "main", "commit": "e91b042b3865d2d040a0e21e0a3b13fb57f24094" }, "sg.nvim": { "branch": "master", "commit": "8bdd4d19da2268072708d5fe18fda9c23e16509d" }, "telescope-fzf-native.nvim": { "branch": "main", "commit": "cf48d4dfce44e0b9a2e19a008d6ec6ea6f01a83b" }, "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, "telescope.nvim": { "branch": "0.1.x", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" }, - "todo-comments.nvim": { "branch": "main", "commit": "8f45f353dc3649cb9b44cecda96827ea88128584" }, - "tokyonight.nvim": { "branch": "main", "commit": "b0e7c7382a7e8f6456f2a95655983993ffda745e" }, - "vim-sleuth": { "branch": "master", "commit": "1cc4557420f215d02c4d2645a748a816c220e99b" }, + "todo-comments.nvim": { "branch": "main", "commit": "319c01b99b7a8c9ac2066bf0efd4d6ec68fef444" }, + "tokyonight.nvim": { "branch": "main", "commit": "4b386e66a9599057587c30538d5e6192e3d1c181" }, + "vim-sleuth": { "branch": "master", "commit": "cd9d382e33bb817abe7f10cdc3a606bf1d491d75" }, "vim-tmux-navigator": { "branch": "master", "commit": "5b3c701686fb4e6629c100ed32e827edf8dad01e" }, - "which-key.nvim": { "branch": "main", "commit": "6c1584eb76b55629702716995cca4ae2798a9cca" }, + "which-key.nvim": { "branch": "main", "commit": "bfec3d6bc0a9b0b2cb11644642f78c2c3915eef0" }, "yazi.nvim": { "branch": "main", "commit": "ac97d7c5e47490ecd179647bc0d0ea04c9ce3329" } } diff --git a/sketchybar/.config/sketchybar/bar.lua b/sketchybar/.config/sketchybar/bar.lua new file mode 100644 index 0000000..13a3bdc --- /dev/null +++ b/sketchybar/.config/sketchybar/bar.lua @@ -0,0 +1,10 @@ +local colors = require("colors") + +-- Equivalent to the --bar domain +sbar.bar({ + topmost = "window", + height = 50, + color = colors.bar.bg, + padding_right = 3, + padding_left = 3, +}) diff --git a/sketchybar/.config/sketchybar/colors.lua b/sketchybar/.config/sketchybar/colors.lua new file mode 100644 index 0000000..2a3d257 --- /dev/null +++ b/sketchybar/.config/sketchybar/colors.lua @@ -0,0 +1,28 @@ +return { + black = 0xff25273A, + white = 0xffb5c9ff, + red = 0xffFF6C8D, + green = 0xff90D05A, + blue = 0xff6EA3FE, + yellow = 0xffE9AD5B, + orange = 0xffFF9856, + magenta = 0xffC198FD, + grey = 0xff9AA9D9, + transparent = 0x00000000, + + bar = { + bg = 0x00ffffff, + border = 0x00ffffff, + }, + popup = { + bg = 0xee25273A, + border = 0xff1E2030, + }, + bg1 = 0xff25273A, + bg2 = 0xff1E2030, + + with_alpha = function(color, alpha) + if alpha > 1.0 or alpha < 0.0 then return color end + return (color & 0x00ffffff) | (math.floor(alpha * 255.0) << 24) + end, +} diff --git a/sketchybar/.config/sketchybar/default.lua b/sketchybar/.config/sketchybar/default.lua new file mode 100644 index 0000000..33e0bf9 --- /dev/null +++ b/sketchybar/.config/sketchybar/default.lua @@ -0,0 +1,52 @@ +local settings = require("settings") +local colors = require("colors") + +-- Equivalent to the --default domain +sbar.default({ + updates = "when_shown", + icon = { + font = { + family = settings.font.text, + style = settings.font.style_map["Bold"], + size = 14.0 + }, + color = colors.white, + padding_left = settings.paddings, + padding_right = settings.paddings, + background = { image = { corner_radius = 9 } }, + }, + label = { + font = { + family = settings.font.text, + style = settings.font.style_map["Semibold"], + size = 13.0 + }, + color = colors.white, + padding_left = settings.paddings, + padding_right = settings.paddings, + }, + background = { + height = 34, + corner_radius = 12, + border_width = 0, + border_color = colors.bg2, + image = { + corner_radius = 9, + border_color = colors.grey, + border_width = 0 + } + }, + popup = { + background = { + border_width = 0, + corner_radius = 9, + border_color = colors.popup.border, + color = colors.popup.bg, + shadow = { drawing = true }, + }, + blur_radius = 50, + }, + padding_left = 5, + padding_right = 5, + scroll_texts = true, +}) diff --git a/sketchybar/.config/sketchybar/helpers/.gitignore b/sketchybar/.config/sketchybar/helpers/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/.gitignore @@ -0,0 +1 @@ +bin diff --git a/sketchybar/.config/sketchybar/helpers/app_icons.lua b/sketchybar/.config/sketchybar/helpers/app_icons.lua new file mode 100644 index 0000000..59bd241 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/app_icons.lua @@ -0,0 +1,211 @@ +return { + ["Typora"] = ":text:", + ["Orion"] = ":orion:", + ["Orion RC"] = ":orion:", + ["Grammarly Editor"] = ":grammarly:", + ["kitty"] = ":kitty:", + ["ClickUp"] = ":click_up:", + ["Iris"] = ":iris:", + ["PomoDone App"] = ":pomodone:", + ["qutebrowser"] = ":qute_browser:", + ["Raindrop.io"] = ":raindrop_io:", + ["Airmail"] = ":airmail:", + ["Affinity Publisher 2"] = ":affinity_publisher_2:", + ["Calendar"] = ":calendar:", + ["日历"] = ":calendar:", + ["Fantastical"] = ":calendar:", + ["Cron"] = ":calendar:", + ["Amie"] = ":calendar:", + ["Figma"] = ":figma:", + ["Element"] = ":element:", + ["Signal"] = ":signal:", + ["Mattermost"] = ":mattermost:", + ["Caprine"] = ":caprine:", + ["Microsoft To Do"] = ":things:", + ["Things"] = ":things:", + ["Godot"] = ":godot:", + ["Android Messages"] = ":android_messages:", + ["Zed"] = ":zed:", + ["Anytype"] = ":anytype:", + ["TeamSpeak 3"] = ":team_speak:", + ["LibreWolf"] = ":libre_wolf:", + ["Neovide"] = ":neovide:", + ["neovide"] = ":neovide:", + ["Spotlight"] = ":spotlight:", + ["微信"] = ":wechat:", + ["Dropbox"] = ":dropbox:", + ["Transmit"] = ":transmit:", + ["TickTick"] = ":tick_tick:", + ["Parallels Desktop"] = ":parallels:", + ["Audacity"] = ":audacity:", + ["Rider"] = ":rider:", + ["JetBrains Rider"] = ":rider:", + ["DEVONthink 3"] = ":devonthink3:", + ["Docker"] = ":docker:", + ["Docker Desktop"] = ":docker:", + ["Matlab"] = ":matlab:", + ["VLC"] = ":vlc:", + ["Alacritty"] = ":alacritty:", + ["Pages"] = ":pages:", + ["Pages 文稿"] = ":pages:", + ["Bear"] = ":bear:", + ["Pine"] = ":pine:", + ["Affinity Designer 2"] = ":affinity_designer_2:", + ["Keyboard Maestro"] = ":keyboard_maestro:", + ["Joplin"] = ":joplin:", + ["mpv"] = ":mpv:", + ["zoom.us"] = ":zoom:", + ["Affinity Photo 2"] = ":affinity_photo_2:", + ["Music"] = ":music:", + ["音乐"] = ":music:", + ["League of Legends"] = ":league_of_legends:", + ["Tor Browser"] = ":tor_browser:", + ["Hyper"] = ":hyper:", + ["‎WhatsApp"] = ":whats_app:", + ["카카오톡"] = ":kakaotalk:", + ["Discord"] = ":discord:", + ["Discord Canary"] = ":discord:", + ["Discord PTB"] = ":discord:", + ["Neovide"] = ":vim:", + ["MacVim"] = ":vim:", + ["Vim"] = ":vim:", + ["VimR"] = ":vim:", + ["Keynote"] = ":keynote:", + ["Keynote 讲演"] = ":keynote:", + ["iTerm"] = ":iterm:", + ["IntelliJ IDEA"] = ":idea:", + ["Finder"] = ":finder:", + ["访达"] = ":finder:", + ["Xcode"] = ":xcode:", + ["GoLand"] = ":goland:", + ["Android Studio"] = ":android_studio:", + ["MoneyMoney"] = ":bank:", + ["Spotify"] = ":spotify:", + ["KeePassXC"] = ":kee_pass_x_c:", + ["Alfred"] = ":alfred:", + ["Color Picker"] = ":color_picker:", + ["数码测色计"] = ":color_picker:", + ["Microsoft Word"] = ":microsoft_word:", + ["Microsoft PowerPoint"] = ":microsoft_power_point:", + ["Notes"] = ":notes:", + ["备忘录"] = ":notes:", + ["Microsoft Edge"] = ":microsoft_edge:", + ["Sublime Text"] = ":sublime_text:", + ["Sequel Ace"] = ":sequel_ace:", + ["Folx"] = ":folx:", + ["DingTalk"] = ":dingtalk:", + ["钉钉"] = ":dingtalk:", + ["阿里钉"] = ":dingtalk:", + ["WebStorm"] = ":web_storm:", + ["Sequel Pro"] = ":sequel_pro:", + ["Skype"] = ":skype:", + ["网易云音乐"] = ":netease_music:", + ["PyCharm"] = ":pycharm:", + ["Canary Mail"] = ":mail:", + ["HEY"] = ":mail:", + ["Mail"] = ":mail:", + ["Mailspring"] = ":mail:", + ["MailMate"] = ":mail:", + ["邮件"] = ":mail:", + ["Default"] = ":default:", + ["App Store"] = ":app_store:", + ["Calibre"] = ":book:", + ["Todoist"] = ":todoist:", + ["Emacs"] = ":emacs:", + ["Messenger"] = ":messenger:", + ["Tower"] = ":tower:", + ["VSCodium"] = ":vscodium:", + ["Drafts"] = ":drafts:", + ["Cypress"] = ":cypress:", + ["GitHub Desktop"] = ":git_hub:", + ["Telegram"] = ":telegram:", + ["Firefox Developer Edition"] = ":firefox_developer_edition:", + ["Firefox Nightly"] = ":firefox_developer_edition:", + ["Min"] = ":min_browser:", + ["Sketch"] = ":sketch:", + ["Affinity Photo"] = ":affinity_photo:", + ["MAMP"] = ":mamp:", + ["MAMP PRO"] = ":mamp:", + ["Insomnia"] = ":insomnia:", + ["Bitwarden"] = ":bit_warden:", + ["Warp"] = ":warp:", + ["System Preferences"] = ":gear:", + ["System Settings"] = ":gear:", + ["系统设置"] = ":gear:", + ["Affinity Designer"] = ":affinity_designer:", + ["Live"] = ":ableton:", + ["Arc"] = ":arc:", + ["Chromium"] = ":google_chrome:", + ["Google Chrome"] = ":google_chrome:", + ["Google Chrome Canary"] = ":google_chrome:", + ["Jellyfin Media Player"] = ":jellyfin:", + ["Zulip"] = ":zulip:", + ["1Password"] = ":one_password:", + ["FaceTime"] = ":face_time:", + ["FaceTime 通话"] = ":face_time:", + ["Citrix Workspace"] = ":citrix:", + ["Citrix Viewer"] = ":citrix:", + ["Logseq"] = ":logseq:", + ["Reeder"] = ":reeder5:", + ["Code"] = ":code:", + ["Code - Insiders"] = ":code:", + ["Notion"] = ":notion:", + ["Final Cut Pro"] = ":final_cut_pro:", + ["Zotero"] = ":zotero:", + ["Safari"] = ":safari:", + ["Safari浏览器"] = ":safari:", + ["Safari Technology Preview"] = ":safari:", + ["Blender"] = ":blender:", + ["Affinity Publisher"] = ":affinity_publisher:", + ["Spark Desktop"] = ":spark:", + ["Zeplin"] = ":zeplin:", + ["Replit"] = ":replit:", + ["Podcasts"] = ":podcasts:", + ["播客"] = ":podcasts:", + ["NordVPN"] = ":nord_vpn:", + ["Notability"] = ":notability:", + ["Numbers"] = ":numbers:", + ["Numbers 表格"] = ":numbers:", + ["Nova"] = ":nova:", + ["Microsoft Excel"] = ":microsoft_excel:", + ["Trello"] = ":trello:", + ["Pi-hole Remote"] = ":pihole:", + ["Linear"] = ":linear:", + ["CleanMyMac X"] = ":desktop:", + ["GrandTotal"] = ":dollar:", + ["Receipts"] = ":dollar:", + ["Evernote Legacy"] = ":evernote_legacy:", + ["OmniFocus"] = ":omni_focus:", + ["Terminal"] = ":terminal:", + ["终端"] = ":terminal:", + ["Atom"] = ":atom:", + ["Kakoune"] = ":kakoune:", + ["Reminders"] = ":reminders:", + ["提醒事项"] = ":reminders:", + ["Tana"] = ":tana:", + ["OBS"] = ":obsstudio:", + ["VMware Fusion"] = ":vmware_fusion:", + ["Tweetbot"] = ":twitter:", + ["Twitter"] = ":twitter:", + ["Microsoft Teams"] = ":microsoft_teams:", + ["Yuque"] = ":yuque:", + ["语雀"] = ":yuque:", + ["Slack"] = ":slack:", + ["Vivaldi"] = ":vivaldi:", + ["Setapp"] = ":setapp:", + ["TIDAL"] = ":tidal:", + ["Miro"] = ":miro:", + ["Messages"] = ":messages:", + ["信息"] = ":messages:", + ["Nachrichten"] = ":messages:", + ["Brave Browser"] = ":brave_browser:", + ["Preview"] = ":pdf:", + ["预览"] = ":pdf:", + ["Skim"] = ":pdf:", + ["zathura"] = ":pdf:", + ["Obsidian"] = ":obsidian:", + ["Thunderbird"] = ":thunderbird:", + ["Firefox"] = ":firefox:", + ["WezTerm"] = ":wezterm:", + ["default"] = ":default:", +} diff --git a/sketchybar/.config/sketchybar/helpers/default_font.lua b/sketchybar/.config/sketchybar/helpers/default_font.lua new file mode 100644 index 0000000..683c075 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/default_font.lua @@ -0,0 +1,14 @@ +return { + text = "SF Pro", -- Used for text + numbers = "SF Pro", -- Used for numbers + mono = "BerkeleyMono Nerd Font", + + -- Unified font style map + style_map = { + ["Regular"] = "Regular", + ["Semibold"] = "Semibold", + ["Bold"] = "Bold", + ["Heavy"] = "Heavy", + ["Black"] = "Black", + } +} diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/cpu.h b/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/cpu.h new file mode 100644 index 0000000..413f70f --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/cpu.h @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +struct cpu { + host_t host; + mach_msg_type_number_t count; + host_cpu_load_info_data_t load; + host_cpu_load_info_data_t prev_load; + bool has_prev_load; + + int user_load; + int sys_load; + int total_load; +}; + +static inline void cpu_init(struct cpu* cpu) { + cpu->host = mach_host_self(); + cpu->count = HOST_CPU_LOAD_INFO_COUNT; + cpu->has_prev_load = false; +} + +static inline void cpu_update(struct cpu* cpu) { + kern_return_t error = host_statistics(cpu->host, + HOST_CPU_LOAD_INFO, + (host_info_t)&cpu->load, + &cpu->count ); + + if (error != KERN_SUCCESS) { + printf("Error: Could not read cpu host statistics.\n"); + return; + } + + if (cpu->has_prev_load) { + uint32_t delta_user = cpu->load.cpu_ticks[CPU_STATE_USER] + - cpu->prev_load.cpu_ticks[CPU_STATE_USER]; + + uint32_t delta_system = cpu->load.cpu_ticks[CPU_STATE_SYSTEM] + - cpu->prev_load.cpu_ticks[CPU_STATE_SYSTEM]; + + uint32_t delta_idle = cpu->load.cpu_ticks[CPU_STATE_IDLE] + - cpu->prev_load.cpu_ticks[CPU_STATE_IDLE]; + + cpu->user_load = (double)delta_user / (double)(delta_system + + delta_user + + delta_idle) * 100.0; + + cpu->sys_load = (double)delta_system / (double)(delta_system + + delta_user + + delta_idle) * 100.0; + + cpu->total_load = cpu->user_load + cpu->sys_load; + } + + cpu->prev_load = cpu->load; + cpu->has_prev_load = true; +} diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/cpu_load.c b/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/cpu_load.c new file mode 100644 index 0000000..ee97613 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/cpu_load.c @@ -0,0 +1,41 @@ +#include "cpu.h" +#include "../sketchybar.h" + +int main (int argc, char** argv) { + float update_freq; + if (argc < 3 || (sscanf(argv[2], "%f", &update_freq) != 1)) { + printf("Usage: %s \"\" \"\"\n", argv[0]); + exit(1); + } + + alarm(0); + struct cpu cpu; + cpu_init(&cpu); + + // Setup the event in sketchybar + char event_message[512]; + snprintf(event_message, 512, "--add event '%s'", argv[1]); + sketchybar(event_message); + + char trigger_message[512]; + for (;;) { + // Acquire new info + cpu_update(&cpu); + + // Prepare the event message + snprintf(trigger_message, + 512, + "--trigger '%s' user_load='%d' sys_load='%02d' total_load='%02d'", + argv[1], + cpu.user_load, + cpu.sys_load, + cpu.total_load ); + + // Trigger the event + sketchybar(trigger_message); + + // Wait + usleep(update_freq * 1000000); + } + return 0; +} diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/makefile b/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/makefile new file mode 100644 index 0000000..6366a0f --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/cpu_load/makefile @@ -0,0 +1,5 @@ +bin/cpu_load: cpu_load.c cpu.h ../sketchybar.h | bin + clang -std=c99 -O3 $< -o $@ + +bin: + mkdir bin diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/makefile b/sketchybar/.config/sketchybar/helpers/event_providers/makefile new file mode 100644 index 0000000..8c1ca39 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/makefile @@ -0,0 +1,3 @@ +all: + (cd cpu_load && $(MAKE)) + (cd network_load && $(MAKE)) diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/network_load/makefile b/sketchybar/.config/sketchybar/helpers/event_providers/network_load/makefile new file mode 100644 index 0000000..e464482 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/network_load/makefile @@ -0,0 +1,5 @@ +bin/network_load: network_load.c network.h ../sketchybar.h | bin + clang -std=c99 -O3 $< -o $@ + +bin: + mkdir bin diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/network_load/network.h b/sketchybar/.config/sketchybar/helpers/event_providers/network_load/network.h new file mode 100644 index 0000000..25175e5 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/network_load/network.h @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include + +static char unit_str[3][6] = { { " Bps" }, { "KBps" }, { "MBps" }, }; + +enum unit { + UNIT_BPS, + UNIT_KBPS, + UNIT_MBPS +}; +struct network { + uint32_t row; + struct ifmibdata data; + struct timeval tv_nm1, tv_n, tv_delta; + + int up; + int down; + enum unit up_unit, down_unit; +}; + +static inline void ifdata(uint32_t net_row, struct ifmibdata* data) { + static size_t size = sizeof(struct ifmibdata); + static int32_t data_option[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, 0, IFDATA_GENERAL }; + data_option[4] = net_row; + sysctl(data_option, 6, data, &size, NULL, 0); +} + +static inline void network_init(struct network* net, char* ifname) { + memset(net, 0, sizeof(struct network)); + + static int count_option[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT }; + uint32_t interface_count = 0; + size_t size = sizeof(uint32_t); + sysctl(count_option, 5, &interface_count, &size, NULL, 0); + + for (int i = 0; i < interface_count; i++) { + ifdata(i, &net->data); + if (strcmp(net->data.ifmd_name, ifname) == 0) { + net->row = i; + break; + } + } +} + +static inline void network_update(struct network* net) { + gettimeofday(&net->tv_n, NULL); + timersub(&net->tv_n, &net->tv_nm1, &net->tv_delta); + net->tv_nm1 = net->tv_n; + + uint64_t ibytes_nm1 = net->data.ifmd_data.ifi_ibytes; + uint64_t obytes_nm1 = net->data.ifmd_data.ifi_obytes; + ifdata(net->row, &net->data); + + double time_scale = (net->tv_delta.tv_sec + 1e-6*net->tv_delta.tv_usec); + if (time_scale < 1e-6 || time_scale > 1e2) return; + double delta_ibytes = (double)(net->data.ifmd_data.ifi_ibytes - ibytes_nm1) + / time_scale; + double delta_obytes = (double)(net->data.ifmd_data.ifi_obytes - obytes_nm1) + / time_scale; + + double exponent_ibytes = log10(delta_ibytes); + double exponent_obytes = log10(delta_obytes); + + if (exponent_ibytes < 3) { + net->down_unit = UNIT_BPS; + net->down = delta_ibytes; + } else if (exponent_ibytes < 6) { + net->down_unit = UNIT_KBPS; + net->down = delta_ibytes / 1000.0; + } else if (exponent_ibytes < 9) { + net->down_unit = UNIT_MBPS; + net->down = delta_ibytes / 1000000.0; + } + + if (exponent_obytes < 3) { + net->up_unit = UNIT_BPS; + net->up = delta_obytes; + } else if (exponent_obytes < 6) { + net->up_unit = UNIT_KBPS; + net->up = delta_obytes / 1000.0; + } else if (exponent_obytes < 9) { + net->up_unit = UNIT_MBPS; + net->up = delta_obytes / 1000000.0; + } +} diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/network_load/network_load.c b/sketchybar/.config/sketchybar/helpers/event_providers/network_load/network_load.c new file mode 100644 index 0000000..06afe95 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/network_load/network_load.c @@ -0,0 +1,42 @@ +#include +#include "network.h" +#include "../sketchybar.h" + +int main (int argc, char** argv) { + float update_freq; + if (argc < 4 || (sscanf(argv[3], "%f", &update_freq) != 1)) { + printf("Usage: %s \"\" \"\" \"\"\n", argv[0]); + exit(1); + } + + alarm(0); + // Setup the event in sketchybar + char event_message[512]; + snprintf(event_message, 512, "--add event '%s'", argv[2]); + sketchybar(event_message); + + struct network network; + network_init(&network, argv[1]); + char trigger_message[512]; + for (;;) { + // Acquire new info + network_update(&network); + + // Prepare the event message + snprintf(trigger_message, + 512, + "--trigger '%s' upload='%03d%s' download='%03d%s'", + argv[2], + network.up, + unit_str[network.up_unit], + network.down, + unit_str[network.down_unit]); + + // Trigger the event + sketchybar(trigger_message); + + // Wait + usleep(update_freq * 1000000); + } + return 0; +} diff --git a/sketchybar/.config/sketchybar/helpers/event_providers/sketchybar.h b/sketchybar/.config/sketchybar/helpers/event_providers/sketchybar.h new file mode 100644 index 0000000..72bf06a --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/event_providers/sketchybar.h @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef char* env; + +#define MACH_HANDLER(name) void name(env env) +typedef MACH_HANDLER(mach_handler); + +struct mach_message { + mach_msg_header_t header; + mach_msg_size_t msgh_descriptor_count; + mach_msg_ool_descriptor_t descriptor; +}; + +struct mach_buffer { + struct mach_message message; + mach_msg_trailer_t trailer; +}; + +static mach_port_t g_mach_port = 0; + +static inline mach_port_t mach_get_bs_port() { + mach_port_name_t task = mach_task_self(); + + mach_port_t bs_port; + if (task_get_special_port(task, + TASK_BOOTSTRAP_PORT, + &bs_port ) != KERN_SUCCESS) { + return 0; + } + + char* name = getenv("BAR_NAME"); + if (!name) name = "sketchybar"; + uint32_t lookup_len = 16 + strlen(name); + + char buffer[lookup_len]; + snprintf(buffer, lookup_len, "git.felix.%s", name); + + mach_port_t port; + if (bootstrap_look_up(bs_port, buffer, &port) != KERN_SUCCESS) return 0; + return port; +} + +static inline bool mach_send_message(mach_port_t port, char* message, uint32_t len) { + if (!message || !port) { + return false; + } + + struct mach_message msg = { 0 }; + msg.header.msgh_remote_port = port; + msg.header.msgh_local_port = 0; + msg.header.msgh_id = 0; + msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, + MACH_MSG_TYPE_MAKE_SEND, + 0, + MACH_MSGH_BITS_COMPLEX ); + + msg.header.msgh_size = sizeof(struct mach_message); + msg.msgh_descriptor_count = 1; + msg.descriptor.address = message; + msg.descriptor.size = len * sizeof(char); + msg.descriptor.copy = MACH_MSG_VIRTUAL_COPY; + msg.descriptor.deallocate = false; + msg.descriptor.type = MACH_MSG_OOL_DESCRIPTOR; + + kern_return_t err = mach_msg(&msg.header, + MACH_SEND_MSG, + sizeof(struct mach_message), + 0, + MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL ); + + return err == KERN_SUCCESS; +} + +static inline uint32_t format_message(char* message, char* formatted_message) { + // This is not actually robust, switch to stack based messaging. + char outer_quote = 0; + uint32_t caret = 0; + uint32_t message_length = strlen(message) + 1; + for (int i = 0; i < message_length; ++i) { + if (message[i] == '"' || message[i] == '\'') { + if (outer_quote && outer_quote == message[i]) outer_quote = 0; + else if (!outer_quote) outer_quote = message[i]; + continue; + } + formatted_message[caret] = message[i]; + if (message[i] == ' ' && !outer_quote) formatted_message[caret] = '\0'; + caret++; + } + + if (caret > 0 && formatted_message[caret] == '\0' + && formatted_message[caret - 1] == '\0') { + caret--; + } + formatted_message[caret] = '\0'; + return caret + 1; +} + +static inline void sketchybar(char* message) { + char formatted_message[strlen(message) + 2]; + uint32_t length = format_message(message, formatted_message); + if (!length) return; + + if (!g_mach_port) g_mach_port = mach_get_bs_port(); + if (!mach_send_message(g_mach_port, formatted_message, length)) { + g_mach_port = mach_get_bs_port(); + if (!mach_send_message(g_mach_port, formatted_message, length)) { + // No sketchybar instance running, exit. + exit(0); + } + } +} diff --git a/sketchybar/.config/sketchybar/helpers/init.lua b/sketchybar/.config/sketchybar/helpers/init.lua new file mode 100644 index 0000000..351531a --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/init.lua @@ -0,0 +1,4 @@ +-- Add the sketchybar module to the package cpath +package.cpath = package.cpath .. ";/Users/" .. os.getenv("USER") .. "/.local/share/sketchybar_lua/?.so" + +os.execute("(cd helpers && make)") diff --git a/sketchybar/.config/sketchybar/helpers/install.sh b/sketchybar/.config/sketchybar/helpers/install.sh new file mode 100755 index 0000000..cdde4ad --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/install.sh @@ -0,0 +1,17 @@ +# Packages +brew install lua +brew install switchaudio-osx +brew install nowplaying-cli + +brew tap FelixKratz/formulae +brew install sketchybar + +# Fonts +brew install --cask sf-symbols +brew install --cask homebrew/cask-fonts/font-sf-mono +brew install --cask homebrew/cask-fonts/font-sf-pro + +curl -L https://github.com/kvndrsslr/sketchybar-app-font/releases/download/v2.0.5/sketchybar-app-font.ttf -o $HOME/Library/Fonts/sketchybar-app-font.ttf + +# SbarLua +(git clone https://github.com/FelixKratz/SbarLua.git /tmp/SbarLua && cd /tmp/SbarLua/ && make install && rm -rf /tmp/SbarLua/) diff --git a/sketchybar/.config/sketchybar/helpers/makefile b/sketchybar/.config/sketchybar/helpers/makefile new file mode 100644 index 0000000..3246108 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/makefile @@ -0,0 +1,3 @@ +all: + (cd event_providers && $(MAKE)) >/dev/null + (cd menus && $(MAKE)) >/dev/null diff --git a/sketchybar/.config/sketchybar/helpers/menus/makefile b/sketchybar/.config/sketchybar/helpers/menus/makefile new file mode 100644 index 0000000..0cb454e --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/menus/makefile @@ -0,0 +1,5 @@ +bin/menus: menus.c | bin + clang -std=c99 -O3 -F/System/Library/PrivateFrameworks/ -framework Carbon -framework SkyLight $< -o $@ + +bin: + mkdir bin diff --git a/sketchybar/.config/sketchybar/helpers/menus/menus.c b/sketchybar/.config/sketchybar/helpers/menus/menus.c new file mode 100644 index 0000000..2e77822 --- /dev/null +++ b/sketchybar/.config/sketchybar/helpers/menus/menus.c @@ -0,0 +1,248 @@ +#include + +void ax_init() { + const void *keys[] = { kAXTrustedCheckOptionPrompt }; + const void *values[] = { kCFBooleanTrue }; + + CFDictionaryRef options; + options = CFDictionaryCreate(kCFAllocatorDefault, + keys, + values, + sizeof(keys) / sizeof(*keys), + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks ); + + bool trusted = AXIsProcessTrustedWithOptions(options); + CFRelease(options); + if (!trusted) exit(1); +} + +void ax_perform_click(AXUIElementRef element) { + if (!element) return; + AXUIElementPerformAction(element, kAXCancelAction); + usleep(150000); + AXUIElementPerformAction(element, kAXPressAction); +} + +CFStringRef ax_get_title(AXUIElementRef element) { + CFTypeRef title = NULL; + AXError error = AXUIElementCopyAttributeValue(element, + kAXTitleAttribute, + &title ); + + if (error != kAXErrorSuccess) return NULL; + return title; +} + +void ax_select_menu_option(AXUIElementRef app, int id) { + AXUIElementRef menubars_ref = NULL; + CFArrayRef children_ref = NULL; + + AXError error = AXUIElementCopyAttributeValue(app, + kAXMenuBarAttribute, + (CFTypeRef*)&menubars_ref); + if (error == kAXErrorSuccess) { + error = AXUIElementCopyAttributeValue(menubars_ref, + kAXVisibleChildrenAttribute, + (CFTypeRef*)&children_ref ); + + if (error == kAXErrorSuccess) { + uint32_t count = CFArrayGetCount(children_ref); + if (id < count) { + AXUIElementRef item = CFArrayGetValueAtIndex(children_ref, id); + ax_perform_click(item); + } + if (children_ref) CFRelease(children_ref); + } + if (menubars_ref) CFRelease(menubars_ref); + } +} + +void ax_print_menu_options(AXUIElementRef app) { + AXUIElementRef menubars_ref = NULL; + CFTypeRef menubar = NULL; + CFArrayRef children_ref = NULL; + + AXError error = AXUIElementCopyAttributeValue(app, + kAXMenuBarAttribute, + (CFTypeRef*)&menubars_ref); + if (error == kAXErrorSuccess) { + error = AXUIElementCopyAttributeValue(menubars_ref, + kAXVisibleChildrenAttribute, + (CFTypeRef*)&children_ref ); + + if (error == kAXErrorSuccess) { + uint32_t count = CFArrayGetCount(children_ref); + + for (int i = 1; i < count; i++) { + AXUIElementRef item = CFArrayGetValueAtIndex(children_ref, i); + CFTypeRef title = ax_get_title(item); + + if (title) { + uint32_t buffer_len = 2*CFStringGetLength(title); + char buffer[2*CFStringGetLength(title)]; + CFStringGetCString(title, buffer, buffer_len, kCFStringEncodingUTF8); + printf("%s\n", buffer); + CFRelease(title); + } + } + } + if (menubars_ref) CFRelease(menubars_ref); + if (children_ref) CFRelease(children_ref); + } +} + +AXUIElementRef ax_get_extra_menu_item(char* alias) { + pid_t pid = 0; + CGRect bounds = CGRectNull; + CFArrayRef window_list = CGWindowListCopyWindowInfo(kCGWindowListOptionAll, + kCGNullWindowID ); + char owner_buffer[256]; + char name_buffer[256]; + char buffer[512]; + int window_count = CFArrayGetCount(window_list); + for (int i = 0; i < window_count; ++i) { + CFDictionaryRef dictionary = CFArrayGetValueAtIndex(window_list, i); + if (!dictionary) continue; + + CFStringRef owner_ref = CFDictionaryGetValue(dictionary, + kCGWindowOwnerName); + + CFNumberRef owner_pid_ref = CFDictionaryGetValue(dictionary, + kCGWindowOwnerPID); + + CFStringRef name_ref = CFDictionaryGetValue(dictionary, kCGWindowName); + CFNumberRef layer_ref = CFDictionaryGetValue(dictionary, kCGWindowLayer); + CFDictionaryRef bounds_ref = CFDictionaryGetValue(dictionary, + kCGWindowBounds); + + if (!name_ref || !owner_ref || !owner_pid_ref || !layer_ref || !bounds_ref) + continue; + + long long int layer = 0; + CFNumberGetValue(layer_ref, CFNumberGetType(layer_ref), &layer); + uint64_t owner_pid = 0; + CFNumberGetValue(owner_pid_ref, + CFNumberGetType(owner_pid_ref), + &owner_pid ); + + if (layer != 0x19) continue; + bounds = CGRectNull; + if (!CGRectMakeWithDictionaryRepresentation(bounds_ref, &bounds)) continue; + CFStringGetCString(owner_ref, + owner_buffer, + sizeof(owner_buffer), + kCFStringEncodingUTF8); + + CFStringGetCString(name_ref, + name_buffer, + sizeof(name_buffer), + kCFStringEncodingUTF8); + snprintf(buffer, sizeof(buffer), "%s,%s", owner_buffer, name_buffer); + + if (strcmp(buffer, alias) == 0) { + pid = owner_pid; + break; + } + } + CFRelease(window_list); + if (!pid) return NULL; + + AXUIElementRef app = AXUIElementCreateApplication(pid); + if (!app) return NULL; + AXUIElementRef result = NULL; + CFTypeRef extras = NULL; + CFArrayRef children_ref = NULL; + AXError error = AXUIElementCopyAttributeValue(app, + kAXExtrasMenuBarAttribute, + &extras ); + if (error == kAXErrorSuccess) { + error = AXUIElementCopyAttributeValue(extras, + kAXVisibleChildrenAttribute, + (CFTypeRef*)&children_ref ); + + if (error == kAXErrorSuccess) { + uint32_t count = CFArrayGetCount(children_ref); + for (uint32_t i = 0; i < count; i++) { + AXUIElementRef item = CFArrayGetValueAtIndex(children_ref, i); + CFTypeRef position_ref = NULL; + CFTypeRef size_ref = NULL; + AXUIElementCopyAttributeValue(item, kAXPositionAttribute, + &position_ref ); + AXUIElementCopyAttributeValue(item, kAXSizeAttribute, + &size_ref ); + if (!position_ref || !size_ref) continue; + + CGPoint position = CGPointZero; + AXValueGetValue(position_ref, kAXValueCGPointType, &position); + CGSize size = CGSizeZero; + AXValueGetValue(size_ref, kAXValueCGSizeType, &size); + CFRelease(position_ref); + CFRelease(size_ref); + // The offset is exactly 8 on macOS Sonoma... + // printf("%f %f\n", position.x, bounds.origin.x); + if (error == kAXErrorSuccess + && fabs(position.x - bounds.origin.x) <= 10) { + result = item; + break; + } + } + } + } + + CFRelease(app); + return result; +} + +extern int SLSMainConnectionID(); +extern void SLSSetMenuBarVisibilityOverrideOnDisplay(int cid, int did, bool enabled); +extern void SLSSetMenuBarVisibilityOverrideOnDisplay(int cid, int did, bool enabled); +extern void SLSSetMenuBarInsetAndAlpha(int cid, double u1, double u2, float alpha); +void ax_select_menu_extra(char* alias) { + AXUIElementRef item = ax_get_extra_menu_item(alias); + if (!item) return; + SLSSetMenuBarInsetAndAlpha(SLSMainConnectionID(), 0, 1, 0.0); + SLSSetMenuBarVisibilityOverrideOnDisplay(SLSMainConnectionID(), 0, true); + SLSSetMenuBarInsetAndAlpha(SLSMainConnectionID(), 0, 1, 0.0); + ax_perform_click(item); + SLSSetMenuBarVisibilityOverrideOnDisplay(SLSMainConnectionID(), 0, false); + SLSSetMenuBarInsetAndAlpha(SLSMainConnectionID(), 0, 1, 1.0); + CFRelease(item); +} + +extern void _SLPSGetFrontProcess(ProcessSerialNumber* psn); +extern void SLSGetConnectionIDForPSN(int cid, ProcessSerialNumber* psn, int* cid_out); +extern void SLSConnectionGetPID(int cid, pid_t* pid_out); +AXUIElementRef ax_get_front_app() { + ProcessSerialNumber psn; + _SLPSGetFrontProcess(&psn); + int target_cid; + SLSGetConnectionIDForPSN(SLSMainConnectionID(), &psn, &target_cid); + + pid_t pid; + SLSConnectionGetPID(target_cid, &pid); + return AXUIElementCreateApplication(pid); +} + +int main (int argc, char **argv) { + if (argc == 1) { + printf("Usage: %s [-l | -s id/alias ]\n", argv[0]); + exit(0); + } + ax_init(); + if (strcmp(argv[1], "-l") == 0) { + AXUIElementRef app = ax_get_front_app(); + if (!app) return 1; + ax_print_menu_options(app); + CFRelease(app); + } else if (argc == 3 && strcmp(argv[1], "-s") == 0) { + int id = 0; + if (sscanf(argv[2], "%d", &id) == 1) { + AXUIElementRef app = ax_get_front_app(); + if (!app) return 1; + ax_select_menu_option(app, id); + CFRelease(app); + } else ax_select_menu_extra(argv[2]); + } + return 0; +} diff --git a/sketchybar/.config/sketchybar/icons.lua b/sketchybar/.config/sketchybar/icons.lua new file mode 100644 index 0000000..e273178 --- /dev/null +++ b/sketchybar/.config/sketchybar/icons.lua @@ -0,0 +1,93 @@ +local settings = require("settings") + +local icons = { + sf_symbols = { + plus = "􀅼", + loading = "􀖇", + apple = "􀣺", + gear = "􀍟", + cpu = "􀫥", + clipboard = "􀉄", + + switch = { + on = "􁏮", + off = "􁏯", + }, + volume = { + _100="􀊩", + _66="􀊧", + _33="􀊥", + _10="􀊡", + _0="􀊣", + }, + battery = { + _100 = "■■■■■■", + _80 = "■■■■□", + _60 = "■■■□□", + _40 = "■■□□□", + _20 = "■□□□□", + _0 = "◧□□□□", + charging = "charging" + }, + wifi = { + upload = "􀄨", + download = "􀄩", + connected = "􀙇", + disconnected = "􀙈", + router = "􁓤", + }, + media = { + back = "􀊊", + forward = "􀊌", + play_pause = "􀊈", + }, + }, + + -- Alternative NerdFont icons + nerdfont = { + plus = "", + loading = "", + apple = "", + gear = "", + cpu = "", + clipboard = "Missing Icon", + + switch = { + on = "󱨥", + off = "󱨦", + }, + volume = { + _100="", + _66="", + _33="", + _10="", + _0="", + }, + battery = { + _100 = "", + _75 = "", + _50 = "", + _25 = "", + _0 = "", + charging = "" + }, + wifi = { + upload = "", + download = "", + connected = "󰖩", + disconnected = "󰖪", + router = "Missing Icon" + }, + media = { + back = "", + forward = "", + play_pause = "", + }, + }, +} + +if not (settings.icons == "NerdFont") then + return icons.sf_symbols +else + return icons.nerdfont +end diff --git a/sketchybar/.config/sketchybar/init.lua b/sketchybar/.config/sketchybar/init.lua new file mode 100644 index 0000000..e1bf892 --- /dev/null +++ b/sketchybar/.config/sketchybar/init.lua @@ -0,0 +1,16 @@ +-- Require the sketchybar module +sbar = require("sketchybar") + +-- Set the bar name, if you are using another bar instance than sketchybar +-- sbar.set_bar_name("bottom_bar") + +-- Bundle the entire initial configuration into a single message to sketchybar +sbar.begin_config() +require("bar") +require("default") +require("items") +sbar.end_config() + +-- Run the event loop of the sketchybar module (without this there will be no +-- callback functions executed in the lua module) +sbar.event_loop() diff --git a/sketchybar/.config/sketchybar/items/apple.lua b/sketchybar/.config/sketchybar/items/apple.lua new file mode 100644 index 0000000..bbe9be9 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/apple.lua @@ -0,0 +1,27 @@ +local colors = require("colors") +local icons = require("icons") +local settings = require("settings") + +-- Padding item required because of bracket +sbar.add("item", { width = 5 }) + +local apple = sbar.add("item", { + icon = { + font = { size = 16.0 }, + string = icons.apple, + padding_right = 12, + padding_left = 10, + }, + label = { drawing = false }, + background = { + color = colors.bg2, + border_color = colors.black, + border_width = 3 + }, + padding_left = 1, + padding_right = 1, + click_script = "$CONFIG_DIR/helpers/menus/bin/menus -s 0" +}) + +-- Padding item required because of bracket +sbar.add("item", { width = 7 }) diff --git a/sketchybar/.config/sketchybar/items/calendar.lua b/sketchybar/.config/sketchybar/items/calendar.lua new file mode 100644 index 0000000..b4cb4e4 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/calendar.lua @@ -0,0 +1,47 @@ +local settings = require("settings") +local colors = require("colors") + +-- Padding item required because of bracket +sbar.add("item", { position = "right", width = settings.group_paddings }) + +local cal = sbar.add("item", { + icon = { + color = colors.white, + padding_left = 12, + font = { + style = settings.font.style_map["Bold"], + size = 14.0, + }, + }, + label = { + color = colors.white, + padding_right = 16, + width = 70, + align = "right", + font = { family = settings.font.numbers }, + }, + position = "right", + update_freq = 30, + padding_left = 1, + padding_right = 1, + background = { + color = colors.bg2, + border_color = colors.black, + border_width = 3 + }, +}) + +-- Double border for calendar using a single item bracket +sbar.add("bracket", { cal.name }, { + background = { + color = colors.transparent, + border_color = colors.grey, + } +}) + +-- Padding item required because of bracket +sbar.add("item", { position = "right", width = settings.group_paddings }) + +cal:subscribe({ "forced", "routine", "system_woke" }, function(env) + cal:set({ icon = os.date("􀉉 %A %d %B"), label = os.date(" 􀐫 %H:%M") }) +end) diff --git a/sketchybar/.config/sketchybar/items/init.lua b/sketchybar/.config/sketchybar/items/init.lua new file mode 100644 index 0000000..5cc7c0e --- /dev/null +++ b/sketchybar/.config/sketchybar/items/init.lua @@ -0,0 +1,7 @@ +require("items.apple") +require("items.menus") +require("items.spaces") +-- require("items.space_mode") +require("items.calendar") +require("items.widgets") +require("items.media") diff --git a/sketchybar/.config/sketchybar/items/media.lua b/sketchybar/.config/sketchybar/items/media.lua new file mode 100644 index 0000000..adcaea2 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/media.lua @@ -0,0 +1,118 @@ +local icons = require("icons") +local colors = require("colors") + +local whitelist = { ["Spotify"] = true, + ["Music"] = true }; + +local media_cover = sbar.add("item", { + position = "right", + background = { + image = { + string = "media.artwork", + scale = 0.85, + }, + color = colors.transparent, + }, + label = { drawing = false }, + icon = { drawing = false }, + drawing = false, + updates = true, + popup = { + align = "center", + horizontal = true, + } +}) + +local media_artist = sbar.add("item", { + position = "right", + drawing = false, + padding_left = 3, + padding_right = 0, + width = 0, + icon = { drawing = false }, + label = { + width = 0, + font = { size = 9 }, + color = colors.with_alpha(colors.white, 0.6), + max_chars = 18, + y_offset = 6, + }, +}) + +local media_title = sbar.add("item", { + position = "right", + drawing = false, + padding_left = 3, + padding_right = 0, + icon = { drawing = false }, + label = { + font = { size = 11 }, + width = 0, + max_chars = 16, + y_offset = -5, + }, +}) + +sbar.add("item", { + position = "popup." .. media_cover.name, + icon = { string = icons.media.back }, + label = { drawing = false }, + click_script = "nowplaying-cli previous", +}) +sbar.add("item", { + position = "popup." .. media_cover.name, + icon = { string = icons.media.play_pause }, + label = { drawing = false }, + click_script = "nowplaying-cli togglePlayPause", +}) +sbar.add("item", { + position = "popup." .. media_cover.name, + icon = { string = icons.media.forward }, + label = { drawing = false }, + click_script = "nowplaying-cli next", +}) + +local interrupt = 0 +local function animate_detail(detail) + if (not detail) then interrupt = interrupt - 1 end + if interrupt > 0 and (not detail) then return end + + sbar.animate("tanh", 30, function() + media_artist:set({ label = { width = detail and "dynamic" or 0 } }) + media_title:set({ label = { width = detail and "dynamic" or 0 } }) + end) +end + +media_cover:subscribe("media_change", function(env) + if whitelist[env.INFO.app] then + local drawing = (env.INFO.state == "playing") + media_artist:set({ drawing = drawing, label = env.INFO.artist, }) + media_title:set({ drawing = drawing, label = env.INFO.title, }) + media_cover:set({ drawing = drawing }) + + if drawing then + animate_detail(true) + interrupt = interrupt + 1 + sbar.delay(5, animate_detail) + else + media_cover:set({ popup = { drawing = false } }) + end + end +end) + +media_cover:subscribe("mouse.entered", function(env) + interrupt = interrupt + 1 + animate_detail(true) +end) + +media_cover:subscribe("mouse.exited", function(env) + animate_detail(false) +end) + +media_cover:subscribe("mouse.clicked", function(env) + media_cover:set({ popup = { drawing = "toggle" }}) +end) + +media_title:subscribe("mouse.exited.global", function(env) + media_cover:set({ popup = { drawing = false }}) +end) diff --git a/sketchybar/.config/sketchybar/items/menus.lua b/sketchybar/.config/sketchybar/items/menus.lua new file mode 100644 index 0000000..22ca528 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/menus.lua @@ -0,0 +1,76 @@ +local colors = require("colors") +local icons = require("icons") +local settings = require("settings") + +local menu_watcher = sbar.add("item", { + drawing = false, + updates = false, +}) +local space_menu_swap = sbar.add("item", { + drawing = false, + updates = true, +}) +sbar.add("event", "swap_menus_and_spaces") + +local max_items = 15 +local menu_items = {} +for i = 1, max_items, 1 do + local menu = sbar.add("item", "menu." .. i, { + padding_left = settings.paddings, + padding_right = settings.paddings, + drawing = false, + icon = { drawing = false }, + label = { + font = { + style = settings.font.style_map[i == 1 and "Heavy" or "Semibold"] + }, + padding_left = 6, + padding_right = 6, + }, + click_script = "$CONFIG_DIR/helpers/menus/bin/menus -s " .. i, + }) + + menu_items[i] = menu +end + +sbar.add("bracket", { '/menu\\..*/' }, { + background = { color = colors.bg1 } +}) + +local menu_padding = sbar.add("item", "menu.padding", { + drawing = false, + width = 5 +}) + +local function update_menus(env) + sbar.exec("$CONFIG_DIR/helpers/menus/bin/menus -l", function(menus) + sbar.set('/menu\\..*/', { drawing = false }) + menu_padding:set({ drawing = true }) + id = 1 + for menu in string.gmatch(menus, '[^\r\n]+') do + if id < max_items then + menu_items[id]:set( { label = menu, drawing = true } ) + else break end + id = id + 1 + end + end) +end + +-- menu_watcher:subscribe("front_app_switched", update_menus) + +-- space_menu_swap:subscribe("swap_menus_and_spaces", function(env) +-- local drawing = menu_items[1]:query().geometry.drawing == "on" +-- if drawing then +-- menu_watcher:set( { updates = false }) +-- sbar.set("/menu\\..*/", { drawing = false }) +-- sbar.set("/space\\..*/", { drawing = true }) +-- sbar.set("front_app", { drawing = true }) +-- else +-- menu_watcher:set( { updates = true }) +-- sbar.set("/space\\..*/", { drawing = false }) +-- sbar.set("front_app", { drawing = false }) +-- update_menus() +-- end +-- end) + +return menu_watcher diff --git a/sketchybar/.config/sketchybar/items/spaces.lua b/sketchybar/.config/sketchybar/items/spaces.lua new file mode 100644 index 0000000..4a245ea --- /dev/null +++ b/sketchybar/.config/sketchybar/items/spaces.lua @@ -0,0 +1,145 @@ +local colors = require("colors") +local icons = require("icons") +local settings = require("settings") +local app_icons = require("helpers.app_icons") + +local spaces = {} + +for i = 1, 10, 1 do + local space = sbar.add("space", "space." .. i, { + space = i, + icon = { + font = { family = settings.font.numbers }, + string = i, + padding_left = 15, + padding_right = 8, + color = colors.white, + highlight_color = colors.red, + }, + label = { + padding_right = 20, + color = colors.grey, + highlight_color = colors.white, + font = "sketchybar-app-font:Regular:16.0", + y_offset = -1, + }, + padding_right = 1, + padding_left = 1, + background = { + color = colors.bg1, + border_width = 3, + border_color = colors.transparent, + }, + popup = { background = { border_width = 5, border_color = colors.black } } + }) + + spaces[i] = space + + -- Padding space + sbar.add("space", "space.padding." .. i, { + space = i, + script = "", + width = settings.group_paddings, + }) + + local space_popup = sbar.add("item", { + position = "popup." .. space.name, + padding_left= 5, + padding_right= 0, + background = { + drawing = true, + image = { + corner_radius = 9, + scale = 0.2 + } + } + }) + + space:subscribe("space_change", function(env) + local selected = env.SELECTED == "true" + local color = selected and colors.red or colors.bg2 + space:set({ + icon = { highlight = selected, }, + label = { highlight = selected }, + background = { border_color = selected and colors.black or colors.bg2 } + }) + space_bracket:set({ + background = { border_color = selected and colors.black or colors.bg2 } + }) + end) + + space:subscribe("mouse.clicked", function(env) + if env.BUTTON == "other" then + space_popup:set({ background = { image = "space." .. env.SID } }) + space:set({ popup = { drawing = "toggle" } }) + else + local op = (env.BUTTON == "right") and "--destroy" or "--focus" + sbar.exec("yabai -m space " .. op .. " " .. env.SID) + end + end) + + space:subscribe("mouse.exited", function(_) + space:set({ popup = { drawing = false } }) + end) +end + +local space_window_observer = sbar.add("item", { + drawing = false, + updates = true, +}) + + +space_window_observer:subscribe("space_windows_change", function(env) + local icon_line = "" + local no_app = true + for app, count in pairs(env.INFO.apps) do + no_app = false + local lookup = app_icons[app] + local icon = ((lookup == nil) and app_icons["default"] or lookup) + icon_line = icon_line .. " " .. icon + end + + if (no_app) then + icon_line = " —" + end + sbar.animate("tanh", 10, function() + spaces[env.INFO.space]:set({ label = icon_line }) + end) +end) + +-- spaces_indicator:subscribe("swap_menus_and_spaces", function(env) +-- local currently_on = spaces_indicator:query().icon.value == icons.switch.on +-- spaces_indicator:set({ +-- icon = currently_on and icons.switch.off or icons.switch.on +-- }) +-- end) + +-- spaces_indicator:subscribe("mouse.entered", function(env) +-- sbar.animate("tanh", 30, function() +-- spaces_indicator:set({ +-- background = { +-- color = { alpha = 1.0 }, +-- border_color = { alpha = 1.0 }, +-- }, +-- icon = { color = colors.bg1 }, +-- label = { width = "dynamic" } +-- }) +-- end) +-- end) + +-- spaces_indicator:subscribe("mouse.exited", function(env) +-- sbar.animate("tanh", 30, function() +-- spaces_indicator:set({ +-- background = { +-- color = { alpha = 0.0 }, +-- border_color = { alpha = 0.0 }, +-- }, +-- icon = { color = colors.grey }, +-- label = { width = 0, } +-- }) +-- end) +-- end) + +-- spaces_indicator:subscribe("mouse.clicked", function(env) +-- sbar.trigger("swap_menus_and_spaces") +-- end) diff --git a/sketchybar/.config/sketchybar/items/widgets/battery.lua b/sketchybar/.config/sketchybar/items/widgets/battery.lua new file mode 100644 index 0000000..8ba4170 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/widgets/battery.lua @@ -0,0 +1,105 @@ +local icons = require("icons") +local colors = require("colors") +local settings = require("settings") + +local battery = sbar.add("item", "widgets.battery", { + position = "right", + icon = { + font = { + style = settings.font.style_map["Regular"], + size = 12.0, + } + }, + label = { font = { family = settings.font.numbers } }, + update_freq = 180, + popup = { align = "center" } +}) + +local remaining_time = sbar.add("item", { + position = "popup." .. battery.name, + icon = { + string = "Time remaining:", + width = 100, + align = "left" + }, + label = { + string = "??:??h", + width = 100, + align = "right" + }, +}) + + +battery:subscribe({"routine", "power_source_change", "system_woke"}, function() + sbar.exec("pmset -g batt", function(batt_info) + local icon = "!" + local label = "?" + + local found, _, charge = batt_info:find("(%d+)%%") + if found then + charge = tonumber(charge) + label = charge .. "%" + end + + local color = colors.green + local charging, _, _ = batt_info:find("AC Power") + + if charging then + icon = icons.battery.charging + else + if found and charge == 0 then + icon = icons.battery._0 + color = colors.red + elseif found and charge <= 20 then + icon = icons.battery._20 + color = colors.orange + elseif found and charge <= 40 then + icon = icons.battery._40 + elseif found and charge <= 60 then + icon = icons.battery._60 + elseif found and charge <= 80 then + icon = icons.battery._80 + elseif found and charge <= 100 then + icon = icons.battery._100 + else + icon = icons.battery._0 + color = colors.red + end + end + + local lead = "" + if found and charge < 10 then + lead = "0" + end + + battery:set({ + icon = { + string = icon, + color = color + }, + label = { string = lead .. label }, + }) + end) +end) + +battery:subscribe("mouse.clicked", function(env) + local drawing = battery:query().popup.drawing + battery:set( { popup = { drawing = "toggle" } }) + + if drawing == "off" then + sbar.exec("pmset -g batt", function(batt_info) + local found, _, remaining = batt_info:find(" (%d+:%d+) remaining") + local label = found and remaining .. "h" or "No estimate" + remaining_time:set( { label = label }) + end) + end +end) + +sbar.add("bracket", "widgets.battery.bracket", { battery.name }, { + background = { color = colors.bg1 } +}) + +sbar.add("item", "widgets.battery.padding", { + position = "right", + width = settings.group_paddings +}) diff --git a/sketchybar/.config/sketchybar/items/widgets/cpu.lua b/sketchybar/.config/sketchybar/items/widgets/cpu.lua new file mode 100644 index 0000000..65b17b4 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/widgets/cpu.lua @@ -0,0 +1,69 @@ +local icons = require("icons") +local colors = require("colors") +local settings = require("settings") + +-- Execute the event provider binary which provides the event "cpu_update" for +-- the cpu load data, which is fired every 2.0 seconds. +sbar.exec("killall cpu_load >/dev/null; $CONFIG_DIR/helpers/event_providers/cpu_load/bin/cpu_load cpu_update 2.0") + +local cpu = sbar.add("graph", "widgets.cpu" , 62, { + position = "right", + graph = { color = colors.blue }, + background = { + height = 22, + color = { alpha = 0 }, + border_color = { alpha = 0 }, + drawing = true, + }, + icon = { string = icons.cpu }, + label = { + string = "cpu ??%", + font = { + family = settings.font.numbers, + style = settings.font.style_map["Bold"], + size = 9.0, + }, + align = "right", + padding_right = 0, + width = 0, + y_offset = 4 + }, + padding_right = settings.paddings + 6 +}) + +cpu:subscribe("cpu_update", function(env) + -- Also available: env.user_load, env.sys_load + local load = tonumber(env.total_load) + cpu:push({ load / 100. }) + + local color = colors.blue + if load > 30 then + if load < 60 then + color = colors.yellow + elseif load < 80 then + color = colors.orange + else + color = colors.red + end + end + + cpu:set({ + graph = { color = color }, + label = "cpu " .. env.total_load .. "%", + }) +end) + +cpu:subscribe("mouse.clicked", function(env) + sbar.exec("open -a 'Activity Monitor'") +end) + +-- Background around the cpu item +sbar.add("bracket", "widgets.cpu.bracket", { cpu.name }, { + background = { color = colors.bg1 } +}) + +-- Background around the cpu item +sbar.add("item", "widgets.cpu.padding", { + position = "right", + width = settings.group_paddings +}) diff --git a/sketchybar/.config/sketchybar/items/widgets/init.lua b/sketchybar/.config/sketchybar/items/widgets/init.lua new file mode 100644 index 0000000..c919c76 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/widgets/init.lua @@ -0,0 +1,4 @@ +require("items.widgets.battery") +require("items.widgets.volume") +require("items.widgets.wifi") +require("items.widgets.cpu") diff --git a/sketchybar/.config/sketchybar/items/widgets/volume.lua b/sketchybar/.config/sketchybar/items/widgets/volume.lua new file mode 100644 index 0000000..7005953 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/widgets/volume.lua @@ -0,0 +1,150 @@ +local colors = require("colors") +local icons = require("icons") +local settings = require("settings") + +local popup_width = 250 + +local volume_percent = sbar.add("item", "widgets.volume1", { + position = "right", + icon = { drawing = false }, + label = { + string = "??%", + padding_left = -1, + font = { family = settings.font.numbers } + }, +}) + +local volume_icon = sbar.add("item", "widgets.volume2", { + position = "right", + padding_right = -1, + icon = { + string = icons.volume._100, + width = 0, + align = "left", + color = colors.grey, + font = { + style = settings.font.style_map["Regular"], + size = 14.0, + }, + }, + label = { + width = 25, + align = "left", + font = { + style = settings.font.style_map["Regular"], + size = 14.0, + }, + }, +}) + +local volume_bracket = sbar.add("bracket", "widgets.volume.bracket", { + volume_icon.name, + volume_percent.name +}, { + background = { color = colors.bg1 }, + popup = { align = "center" } +}) + +sbar.add("item", "widgets.volume.padding", { + position = "right", + width = settings.group_paddings +}) + +local volume_slider = sbar.add("slider", popup_width, { + position = "popup." .. volume_bracket.name, + slider = { + highlight_color = colors.blue, + background = { + height = 6, + corner_radius = 3, + color = colors.bg2, + }, + knob= { + string = "􀀁", + drawing = true, + }, + }, + background = { color = colors.bg1, height = 2, y_offset = -20 }, + click_script = 'osascript -e "set volume output volume $PERCENTAGE"' +}) + +volume_percent:subscribe("volume_change", function(env) + local volume = tonumber(env.INFO) + local icon = icons.volume._0 + if volume > 60 then + icon = icons.volume._100 + elseif volume > 30 then + icon = icons.volume._66 + elseif volume > 10 then + icon = icons.volume._33 + elseif volume > 0 then + icon = icons.volume._10 + end + + local lead = "" + if volume < 10 then + lead = "0" + end + + volume_icon:set({ label = icon }) + volume_percent:set({ label = lead .. volume .. "%" }) + volume_slider:set({ slider = { percentage = volume } }) +end) + +local function volume_collapse_details() + local drawing = volume_bracket:query().popup.drawing == "on" + if not drawing then return end + volume_bracket:set({ popup = { drawing = false } }) + sbar.remove('/volume.device\\.*/') +end + +local current_audio_device = "None" +local function volume_toggle_details(env) + if env.BUTTON == "right" then + sbar.exec("open /System/Library/PreferencePanes/Sound.prefpane") + return + end + + local should_draw = volume_bracket:query().popup.drawing == "off" + if should_draw then + volume_bracket:set({ popup = { drawing = true } }) + sbar.exec("SwitchAudioSource -t output -c", function(result) + current_audio_device = result:sub(1, -2) + sbar.exec("SwitchAudioSource -a -t output", function(available) + current = current_audio_device + local color = colors.grey + local counter = 0 + + for device in string.gmatch(available, '[^\r\n]+') do + local color = colors.grey + if current == device then + color = colors.white + end + sbar.add("item", "volume.device." .. counter, { + position = "popup." .. volume_bracket.name, + width = popup_width, + align = "center", + label = { string = device, color = color }, + click_script = 'SwitchAudioSource -s "' .. device .. '" && sketchybar --set /volume.device\\.*/ label.color=' .. colors.grey .. ' --set $NAME label.color=' .. colors.white + + }) + counter = counter + 1 + end + end) + end) + else + volume_collapse_details() + end +end + +local function volume_scroll(env) + local delta = env.SCROLL_DELTA + sbar.exec('osascript -e "set volume output volume (output volume of (get volume settings) + ' .. delta .. ')"') +end + +-- volume_icon:subscribe("mouse.clicked", volume_toggle_details) +-- volume_icon:subscribe("mouse.scrolled", volume_scroll) +-- volume_percent:subscribe("mouse.clicked", volume_toggle_details) +-- volume_percent:subscribe("mouse.exited.global", volume_collapse_details) +-- volume_percent:subscribe("mouse.scrolled", volume_scroll) + diff --git a/sketchybar/.config/sketchybar/items/widgets/wifi.lua b/sketchybar/.config/sketchybar/items/widgets/wifi.lua new file mode 100644 index 0000000..c558085 --- /dev/null +++ b/sketchybar/.config/sketchybar/items/widgets/wifi.lua @@ -0,0 +1,245 @@ +local icons = require("icons") +local colors = require("colors") +local settings = require("settings") + +-- Execute the event provider binary which provides the event "network_update" +-- for the network interface "en0", which is fired every 2.0 seconds. +sbar.exec("killall network_load >/dev/null; $CONFIG_DIR/helpers/event_providers/network_load/bin/network_load en0 network_update 2.0") + +local popup_width = 250 + +local wifi_up = sbar.add("item", "widgets.wifi1", { + position = "right", + padding_left = -5, + width = 0, + icon = { + padding_right = 0, + font = { + style = settings.font.style_map["Bold"], + size = 9.0, + }, + string = icons.wifi.upload, + }, + label = { + font = { + family = settings.font.mono, + style = settings.font.style_map["Bold"], + size = 9.0, + }, + color = colors.red, + string = "??? Bps", + }, + y_offset = 4, +}) + +local wifi_down = sbar.add("item", "widgets.wifi2", { + position = "right", + padding_left = -5, + icon = { + padding_right = 0, + font = { + style = settings.font.style_map["Bold"], + size = 9.0, + }, + string = icons.wifi.download, + }, + label = { + font = { + family = settings.font.mono, + style = settings.font.style_map["Bold"], + size = 9.0, + }, + color = colors.blue, + string = "??? Bps", + }, + y_offset = -4, +}) + +local wifi = sbar.add("item", "widgets.wifi.padding", { + position = "right", + label = { drawing = true, string = [[HERE]] }, +}) + +-- Background around the item +local wifi_bracket = sbar.add("bracket", "widgets.wifi.bracket", { + wifi.name, + wifi_up.name, + wifi_down.name +}, { + background = { color = colors.bg1 }, + popup = { align = "center", height = 30 } +}) + +local ssid = sbar.add("item", { + position = "popup." .. wifi_bracket.name, + icon = { + font = { + style = settings.font.style_map["Bold"] + }, + string = icons.wifi.router, + }, + width = popup_width, + align = "center", + label = { + font = { + size = 15, + style = settings.font.style_map["Bold"] + }, + max_chars = 18, + string = "????????????", + }, + background = { + height = 2, + color = colors.grey, + y_offset = -15 + } +}) + +local hostname = sbar.add("item", { + position = "popup." .. wifi_bracket.name, + icon = { + align = "left", + string = "Hostname:", + width = popup_width / 2, + }, + label = { + max_chars = 20, + string = "????????????", + width = popup_width / 2, + align = "right", + } +}) + +local ip = sbar.add("item", { + position = "popup." .. wifi_bracket.name, + icon = { + align = "left", + string = "IP:", + width = popup_width / 2, + }, + label = { + string = "???.???.???.???", + width = popup_width / 2, + align = "right", + } +}) + +local mask = sbar.add("item", { + position = "popup." .. wifi_bracket.name, + icon = { + align = "left", + string = "Subnet mask:", + width = popup_width / 2, + }, + label = { + string = "???.???.???.???", + width = popup_width / 2, + align = "right", + } +}) + +local router = sbar.add("item", { + position = "popup." .. wifi_bracket.name, + icon = { + align = "left", + string = "Router:", + width = popup_width / 2, + }, + label = { + string = "???.???.???.???", + width = popup_width / 2, + align = "right", + }, +}) + +sbar.add("item", { position = "right", width = settings.group_paddings }) + +wifi_up:subscribe("network_update", function(env) + local up_color = (env.upload == "000 Bps") and colors.grey or colors.red + local down_color = (env.download == "000 Bps") and colors.grey or colors.blue + wifi_up:set({ + icon = { color = up_color }, + label = { + string = env.upload, + color = up_color + } + }) + wifi_down:set({ + icon = { color = down_color }, + label = { + string = env.download, + color = down_color + } + }) +end) + +wifi:subscribe({"wifi_change", "system_woke"}, function(env) + sbar.exec("ipconfig getifaddr en0", function(ip) + local connected = not (ip == "") + wifi:set({ + icon = { + string = connected and icons.wifi.connected or icons.wifi.disconnected, + color = connected and colors.white or colors.red, + }, + }) + if connected then + sbar.exec("ipconfig getsummary en0 | awk -F ' SSID : ' '/ SSID : / {print $2}'", function(ssid_result) + wifi:set({ + label = { string = ssid_result } + }) + end) + else + wifi:set({ + label = { string = "Disconnected" } + }) + end + end) +end) + +local function hide_details() + wifi_bracket:set({ popup = { drawing = false } }) +end + +local function toggle_details() + local should_draw = wifi_bracket:query().popup.drawing == "off" + if should_draw then + wifi_bracket:set({ popup = { drawing = true }}) + sbar.exec("networksetup -getcomputername", function(result) + hostname:set({ label = result }) + end) + sbar.exec("ipconfig getifaddr en0", function(result) + ip:set({ label = result }) + end) + sbar.exec("ipconfig getsummary en0 | awk -F ' SSID : ' '/ SSID : / {print $2}'", function(result) + ssid:set({ label = result }) + end) + sbar.exec("networksetup -getinfo Wi-Fi | awk -F 'Subnet mask: ' '/^Subnet mask: / {print $2}'", function(result) + mask:set({ label = result }) + end) + sbar.exec("networksetup -getinfo Wi-Fi | awk -F 'Router: ' '/^Router: / {print $2}'", function(result) + router:set({ label = result }) + end) + else + hide_details() + end +end + +wifi_up:subscribe("mouse.clicked", toggle_details) +wifi_down:subscribe("mouse.clicked", toggle_details) +wifi:subscribe("mouse.clicked", toggle_details) +wifi:subscribe("mouse.exited.global", hide_details) + +local function copy_label_to_clipboard(env) + local label = sbar.query(env.NAME).label.value + sbar.exec("echo \"" .. label .. "\" | pbcopy") + sbar.set(env.NAME, { label = { string = icons.clipboard, align="center" } }) + sbar.delay(1, function() + sbar.set(env.NAME, { label = { string = label, align = "right" } }) + end) +end + +ssid:subscribe("mouse.clicked", copy_label_to_clipboard) +hostname:subscribe("mouse.clicked", copy_label_to_clipboard) +ip:subscribe("mouse.clicked", copy_label_to_clipboard) +mask:subscribe("mouse.clicked", copy_label_to_clipboard) +router:subscribe("mouse.clicked", copy_label_to_clipboard) \ No newline at end of file diff --git a/sketchybar/.config/sketchybar/settings.lua b/sketchybar/.config/sketchybar/settings.lua new file mode 100644 index 0000000..7713dc4 --- /dev/null +++ b/sketchybar/.config/sketchybar/settings.lua @@ -0,0 +1,22 @@ +return { + paddings = 3, + group_paddings = 5, + + icons = "sf-symbols", -- alternatively available: NerdFont + + -- This is a font configuration for SF Pro and SF Mono (installed manually) + font = require("helpers.default_font"), + + -- Alternatively, this is a font config for JetBrainsMono Nerd Font + -- font = { + -- text = "JetBrainsMono Nerd Font", -- Used for text + -- numbers = "JetBrainsMono Nerd Font", -- Used for numbers + -- style_map = { + -- ["Regular"] = "Regular", + -- ["Semibold"] = "Medium", + -- ["Bold"] = "SemiBold", + -- ["Heavy"] = "Bold", + -- ["Black"] = "ExtraBold", + -- }, + -- }, +} diff --git a/sketchybar/.config/sketchybar/sketchybarrc b/sketchybar/.config/sketchybar/sketchybarrc new file mode 100755 index 0000000..95ece11 --- /dev/null +++ b/sketchybar/.config/sketchybar/sketchybarrc @@ -0,0 +1,5 @@ +#!/usr/bin/env lua + +-- Load the sketchybar-package and prepare the helper binaries +require("helpers") +require("init") diff --git a/skhd/.config/skhd/skhdrc b/skhd/.config/skhd/skhdrc new file mode 100644 index 0000000..ab626d4 --- /dev/null +++ b/skhd/.config/skhd/skhdrc @@ -0,0 +1,17 @@ +# change window focus +cmd - j : yabai -m window --focus south +cmd - k : yabai -m window --focus north +cmd - h : yabai -m window --focus west +cmd - l : yabai -m window --focus east + +# modify layout +shift + cmd - r : yabai -m space --rotate 270 +shift + cmd - y : yabai -m space --mirror y-axis +shift + cmd - x : yabai -m space --mirror x-axis +shift + cmd - t : yabai -m window --toggle float --grid 4:4:1:1:2:2 + +# maximize a window +shift + cmd - f : yabai -m window --toggle zoom-fullscreen + +# balance windows +shift + cmd - b : yabai -m space --balance diff --git a/wezterm/.wezterm.lua b/wezterm/.wezterm.lua index a0f7da6..65213d1 100644 --- a/wezterm/.wezterm.lua +++ b/wezterm/.wezterm.lua @@ -13,9 +13,10 @@ end -- For example, changing the color scheme: config.color_scheme = "Catppuccin Mocha" -config.font_size = 11 +config.font_size = 14 -config.window_decorations = "TITLE | RESIZE" +-- config.window_decorations = "TITLE | RESIZE" +config.window_decorations = "RESIZE" -- tmux config.keys = { diff --git a/yabai/.config/yabai/yabairc b/yabai/.config/yabai/yabairc new file mode 100644 index 0000000..82cc399 --- /dev/null +++ b/yabai/.config/yabai/yabairc @@ -0,0 +1,33 @@ +yabai -m config layout bsp + +yabai -m config window_placement second_child + +# padding +yabai -m config top_padding 16 +yabai -m config bottom_padding 16 +yabai -m config left_padding 16 +yabai -m config right_padding 16 +yabai -m config window_gap 18 + +# mouse settings +#yabai -m config focus_follows_mouse autoraise +yabai -m config focus_follows_mouse on + +yabai -m config mouse_modifier cmd +yabai -m config mouse_action1 move +yabai -m mouse_action2 resize + +yabai -m mouse_drop_action swap + +# ignore apps +yabai -m rule --add app="^System Settings$" manage=off +yabai -m rule --add app="^Calculator$" manage=off +yabai -m rule --add app="^love$" manage=off +yabai -m rule --add app="^Messages$" manage=off + +# include apps +yabai -m rule --add app="^Unity$" manage=on + +# yabai -m config external_bar all:8:0 + +borders active_color=0xffc6a0f6 inactive_color=0xff24273a width=10.0 blacklist="iPhone Mirroring"&