diff options
| author | Pascal Dulieu <pascal@dulieu.uk> | 2025-07-30 11:45:00 +0100 |
|---|---|---|
| committer | Pascal Dulieu <pascal@dulieu.uk> | 2025-07-30 11:45:00 +0100 |
| commit | c19fa68472bec357914ff264e52b45945221d530 (patch) | |
| tree | 8bb993d3f9bf7b91155300fcc7fe1b282faf7066 | |
49 files changed, 7999 insertions, 0 deletions
diff --git a/.config/nvim/.gitignore b/.config/nvim/.gitignore new file mode 100644 index 0000000..cc5457a --- /dev/null +++ b/.config/nvim/.gitignore @@ -0,0 +1,8 @@ +tt.* +.tests +doc/tags +debug +.repro +foo.* +*.log +data diff --git a/.config/nvim/.neoconf.json b/.config/nvim/.neoconf.json new file mode 100644 index 0000000..7c48087 --- /dev/null +++ b/.config/nvim/.neoconf.json @@ -0,0 +1,15 @@ +{ + "neodev": { + "library": { + "enabled": true, + "plugins": true + } + }, + "neoconf": { + "plugins": { + "lua_ls": { + "enabled": true + } + } + } +} diff --git a/.config/nvim/LICENSE b/.config/nvim/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/.config/nvim/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.config/nvim/README.md b/.config/nvim/README.md new file mode 100644 index 0000000..185280b --- /dev/null +++ b/.config/nvim/README.md @@ -0,0 +1,4 @@ +# 💤 LazyVim + +A starter template for [LazyVim](https://github.com/LazyVim/LazyVim). +Refer to the [documentation](https://lazyvim.github.io/installation) to get started. diff --git a/.config/nvim/colors/lushwal.vim b/.config/nvim/colors/lushwal.vim new file mode 100644 index 0000000..ecf199b --- /dev/null +++ b/.config/nvim/colors/lushwal.vim @@ -0,0 +1,218 @@ +set background=dark +if exists('g:colors_name') +hi clear +if exists('syntax_on') +syntax reset +endif +endif +let g:colors_name = 'lushwal' +highlight Normal guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight! link User Normal +highlight Bold guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=bold +highlight Boolean guifg=#516757 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Character guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight ColorColumn guifg=#738787 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Comment guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=italic +highlight Conceal guifg=#576B6B guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight! link Whitespace Conceal +highlight Conditional guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Constant guifg=#516757 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Cursor guifg=#091515 guibg=#C1C3C3 guisp=NONE blend=NONE gui=NONE +highlight CursorColumn guifg=#738787 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight CursorLine guifg=NONE guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight CursorLineNr guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight Debug guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Define guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Delimiter guifg=#556261 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight DiagnosticError guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight DiagnosticHint guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight DiagnosticInfo guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight DiagnosticUnderlineError guifg=#546064 guibg=NONE guisp=#546064 blend=NONE gui=underline +highlight DiagnosticUnderlineHint guifg=#747873 guibg=NONE guisp=#747873 blend=NONE gui=underline +highlight DiagnosticUnderlineInfo guifg=#5D6365 guibg=NONE guisp=#5D6365 blend=NONE gui=underline +highlight DiagnosticUnderlineWarn guifg=#4C6F49 guibg=NONE guisp=#4C6F49 blend=NONE gui=underline +highlight DiagnosticWarn guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight DiffAdd guifg=#5E5F53 guibg=#576B6B guisp=NONE blend=NONE gui=bold +highlight! link DiffAdded DiffAdd +highlight DiffChange guifg=#9CA5A5 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight DiffDelete guifg=#546064 guibg=#576B6B guisp=NONE blend=NONE gui=bold +highlight! link DiffRemoved DiffDelete +highlight! link diffRemoved DiffDelete +highlight DiffFile guifg=#546064 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight DiffLine guifg=#5D6365 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight DiffNewFile guifg=#5E5F53 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight DiffText guifg=#5D6365 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight Directory guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight EndOfBuffer guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight Error guifg=#546064 guibg=#C1C3C3 guisp=NONE blend=NONE gui=NONE +highlight ErrorMsg guifg=#546064 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight Exception guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Float guifg=#516757 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight FoldColumn guifg=#5D6365 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight Folded guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=italic +highlight Function guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Identifier guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight IncSearch guifg=#576B6B guibg=#516757 guisp=NONE blend=NONE gui=NONE +highlight Include guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Italic guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=italic +highlight Keyword guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Label guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight LineNr guifg=#9CA5A5 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight Macro guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MatchParen guifg=#C1C3C3 guibg=#9CA5A5 guisp=NONE blend=NONE gui=NONE +highlight MiniCompletionActiveParameter guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniCursorword guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=underline +highlight! link MiniCursorwordCurrent MiniCursorword +highlight MiniIndentscopePrefix guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=nocombine +highlight MiniIndentscopeSymbol guifg=#576B6B guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight MiniJump guifg=#5D6365 guibg=NONE guisp=#9CA5A5 blend=NONE gui=underline +highlight MiniJump2dSpot guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=undercurl +highlight MiniStarterCurrent guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniStarterFooter guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=bold +highlight MiniStarterHeader guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=bold +highlight MiniStarterInactive guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=italic +highlight MiniStarterItem guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight MiniStarterItemBullet guifg=#556261 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniStarterItemPrefix guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniStarterQuery guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniStarterSection guifg=#556261 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineDevinfo guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineFileinfo guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineFilename guifg=#4C6F49 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineInactive guifg=#738787 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineModeCommand guifg=#091515 guibg=#747873 guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineModeInsert guifg=#091515 guibg=#5D6365 guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineModeNormal guifg=#091515 guibg=#5E5F53 guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineModeOther guifg=#091515 guibg=#A7A5AC guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineModeReplace guifg=#091515 guibg=#546064 guisp=NONE blend=NONE gui=NONE +highlight MiniStatuslineModeVisual guifg=#091515 guibg=#516757 guisp=NONE blend=NONE gui=NONE +highlight MiniSurround guifg=#576B6B guibg=#516757 guisp=NONE blend=NONE gui=NONE +highlight MiniTablineCurrent guifg=#9CA5A5 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniTablineFill guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MiniTablineHidden guifg=#5E5F53 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniTablineModifiedCurrent guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniTablineModifiedHidden guifg=#738787 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniTablineModifiedVisible guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniTablineVisible guifg=#9CA5A5 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight MiniTestEmphasis guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=bold +highlight MiniTestFail guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=bold +highlight MiniTestPass guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=bold +highlight MiniTrailspace guifg=#546064 guibg=#C1C3C3 guisp=NONE blend=NONE gui=NONE +highlight ModeMsg guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight MoreMsg guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight NonText guifg=#9CA5A5 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Number guifg=#516757 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Operator guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight PMenu guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight PMenuSel guifg=#C1C3C3 guibg=#5D6365 guisp=NONE blend=NONE gui=NONE +highlight PmenuSbar guifg=#738787 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight PmenuThumb guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight PreProc guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Question guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Repeat guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Search guifg=#9CA5A5 guibg=#4C6F49 guisp=NONE blend=NONE gui=NONE +highlight! link MiniTablineTabpagesection Search +highlight SignColumn guifg=#738787 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight Special guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight SpecialChar guifg=#556261 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight SpecialKey guifg=#9CA5A5 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight SpellBad guifg=#546064 guibg=NONE guisp=#546064 blend=NONE gui=underline +highlight SpellCap guifg=#4C6F49 guibg=NONE guisp=#4C6F49 blend=NONE gui=underline +highlight SpellLocal guifg=#747873 guibg=NONE guisp=#747873 blend=NONE gui=underline +highlight SpellRare guifg=#A7A5AC guibg=NONE guisp=#A7A5AC blend=NONE gui=underline +highlight Statement guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight StatusLine guifg=#C1C3C3 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight StatusLineNC guifg=#738787 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight StatusLineTerm guifg=#5E5F53 guibg=#5E5F53 guisp=NONE blend=NONE gui=NONE +highlight StatusLineTermNC guifg=#4C6F49 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight StorageClass guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight String guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Structure guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight TabLine guifg=#9CA5A5 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight TabLineFill guifg=#9CA5A5 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight TabLineSel guifg=#5E5F53 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight Tag guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Title guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=bold +highlight Todo guifg=#4C6F49 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight TooLong guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Type guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Typedef guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight Underlined guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight VertSplit guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight! link WinSeparator VertSplit +highlight Visual guifg=#091515 guibg=#738787 guisp=NONE blend=NONE gui=NONE +highlight VisualNOS guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight WarningMsg guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight WildMenu guifg=#C1C3C3 guibg=#5D6365 guisp=NONE blend=NONE gui=NONE +highlight WinBar guifg=#C1C3C3 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight WinBarNC guifg=#738787 guibg=#091515 guisp=NONE blend=NONE gui=NONE +highlight gitCommitOverflow guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight gitCommitSummary guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight helpCommand guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight helpExample guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @attribute guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @boolean guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @character guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @character.special guifg=#556261 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @comment guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=italic +highlight @conditional guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @constant guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @constant.builtin guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @constant.macro guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @constructor guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @debug guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @define guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @exception guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @field guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @float guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @function guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @function.builtin guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @function.macro guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @include guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @keyword guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @keyword.function guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @keyword.operator guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @label guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @method guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @namespace guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @none guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @number guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @operator guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @parameter guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @preproc guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @property guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @punctuation.bracket guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @punctuation.delimiter guifg=#C1C3C3 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @punctuation.special guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=bold +highlight @repeat guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @storageclass guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @string guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @string.escape guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @string.regex guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @string.special guifg=#556261 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @symbol guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @tag guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @tag.attribute guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @tag.delimiter guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.bold guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=bold +highlight @text.danger guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.diff.add guifg=#5E5F53 guibg=#576B6B guisp=NONE blend=NONE gui=bold +highlight @text.diff.delete guifg=#546064 guibg=#576B6B guisp=NONE blend=NONE gui=bold +highlight @text.emphasis guifg=#A7A5AC guibg=NONE guisp=NONE blend=NONE gui=italic +highlight @text.environment guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.environment.name guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.literal guifg=#5E5F53 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.math guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.note guifg=#747873 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.reference guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @text.strike guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=strikethrough +highlight @text.title guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=bold +highlight @text.todo guifg=#4C6F49 guibg=#576B6B guisp=NONE blend=NONE gui=NONE +highlight @text.underline guifg=NONE guibg=NONE guisp=NONE blend=NONE gui=underline +highlight @text.uri guifg=NONE guibg=#576B6B guisp=NONE blend=NONE gui=underline +highlight @type guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @type.builtin guifg=#5D6365 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @type.definition guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @variable guifg=#4C6F49 guibg=NONE guisp=NONE blend=NONE gui=NONE +highlight @variable.builtin guifg=#546064 guibg=NONE guisp=NONE blend=NONE gui=NONE diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua new file mode 100644 index 0000000..2514f9e --- /dev/null +++ b/.config/nvim/init.lua @@ -0,0 +1,2 @@ +-- bootstrap lazy.nvim, LazyVim and your plugins +require("config.lazy") diff --git a/.config/nvim/lazy-lock.json b/.config/nvim/lazy-lock.json new file mode 100644 index 0000000..f557235 --- /dev/null +++ b/.config/nvim/lazy-lock.json @@ -0,0 +1,38 @@ +{ + "LazyVim": { "branch": "main", "commit": "d72127eb936f7f05d88d4fc316bc7e89080d69d8" }, + "blink.cmp": { "branch": "main", "commit": "327fff91fe6af358e990be7be1ec8b78037d2138" }, + "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" }, + "catppuccin": { "branch": "main", "commit": "8c4125e3c746976ba025dc5d908fa22c6aa09486" }, + "conform.nvim": { "branch": "master", "commit": "9fd3d5e0b689ec1bf400c53cbbec72c6fdf24081" }, + "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" }, + "friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" }, + "gitsigns.nvim": { "branch": "main", "commit": "20ad4419564d6e22b189f6738116b38871082332" }, + "grug-far.nvim": { "branch": "main", "commit": "3e72397465f774b01aa38e4fe8e6eecf23d766d9" }, + "lazy.nvim": { "branch": "main", "commit": "db067881fff0fd4be8c00e5bde7492e0e1c77a2f" }, + "lazydev.nvim": { "branch": "main", "commit": "c2dfe354571a8255c5d3e96a9a4c297c89ce2347" }, + "lualine.nvim": { "branch": "master", "commit": "3946f0122255bc377d14a59b27b609fb3ab25768" }, + "lush.nvim": { "branch": "main", "commit": "9c60ec2279d62487d942ce095e49006af28eed6e" }, + "lushwal.nvim": { "branch": "main", "commit": "2823942833368460c85bb235b4e36789c266e6a2" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "3590d66effccc7376d8c3dbe45e8291f9fed2843" }, + "mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" }, + "mini.ai": { "branch": "main", "commit": "11c57180bc9084089206e211ac7aa598bedc9673" }, + "mini.icons": { "branch": "main", "commit": "284798619aed9f4c1ac1b9417b9a5e3b4b85ef3a" }, + "mini.pairs": { "branch": "main", "commit": "b9aada8c0e59f2b938e98fbf4eae0799eba96ad9" }, + "noice.nvim": { "branch": "main", "commit": "5099348591f7d3ba9e547b1e631c694c65bbe0b9" }, + "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, + "nvim-lint": { "branch": "master", "commit": "9da1fb942dd0668d5182f9c8dee801b9c190e2bb" }, + "nvim-lspconfig": { "branch": "master", "commit": "48a9b4dcd9a3611edddd51972d8abb1a289c7724" }, + "nvim-treesitter": { "branch": "main", "commit": "645f42e85d8665c91a9911c3896afb57d6b8a923" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "1b2d85d3de6114c4bcea89ffb2cd1ce9e3a19931" }, + "nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" }, + "persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" }, + "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, + "project.nvim": { "branch": "main", "commit": "8c6bad7d22eef1b71144b401c9f74ed01526a4fb" }, + "shipwright.nvim": { "branch": "master", "commit": "e596ab48328c31873f4f4d2e070243bf9de16ff3" }, + "snacks.nvim": { "branch": "main", "commit": "14ead48b513207298711224fe70a3abd58fcc190" }, + "todo-comments.nvim": { "branch": "main", "commit": "411503d3bedeff88484de572f2509c248e499b38" }, + "tokyonight.nvim": { "branch": "main", "commit": "2642dbb83333e0575d1c3436e1d837926871c5fb" }, + "trouble.nvim": { "branch": "main", "commit": "d7494d8bc563f8ae8b3f35d78c7478cf842b0ab9" }, + "ts-comments.nvim": { "branch": "main", "commit": "123a9fb12e7229342f807ec9e6de478b1102b041" }, + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } +} diff --git a/.config/nvim/lazyvim.json b/.config/nvim/lazyvim.json new file mode 100644 index 0000000..d8bcaf6 --- /dev/null +++ b/.config/nvim/lazyvim.json @@ -0,0 +1,10 @@ +{ + "extras": [ + + ], + "install_version": 8, + "news": { + "NEWS.md": "11866" + }, + "version": 8 +}
\ No newline at end of file diff --git a/.config/nvim/lua/config/autocmds.lua b/.config/nvim/lua/config/autocmds.lua new file mode 100644 index 0000000..4221e75 --- /dev/null +++ b/.config/nvim/lua/config/autocmds.lua @@ -0,0 +1,8 @@ +-- Autocmds are automatically loaded on the VeryLazy event +-- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua +-- +-- Add any additional autocmds here +-- with `vim.api.nvim_create_autocmd` +-- +-- Or remove existing autocmds by their group name (which is prefixed with `lazyvim_` for the defaults) +-- e.g. vim.api.nvim_del_augroup_by_name("lazyvim_wrap_spell") diff --git a/.config/nvim/lua/config/keymaps.lua b/.config/nvim/lua/config/keymaps.lua new file mode 100644 index 0000000..2c134f7 --- /dev/null +++ b/.config/nvim/lua/config/keymaps.lua @@ -0,0 +1,3 @@ +-- Keymaps are automatically loaded on the VeryLazy event +-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua +-- Add any additional keymaps here diff --git a/.config/nvim/lua/config/lazy.lua b/.config/nvim/lua/config/lazy.lua new file mode 100644 index 0000000..d73bfa1 --- /dev/null +++ b/.config/nvim/lua/config/lazy.lua @@ -0,0 +1,53 @@ +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + { "\nPress any key to exit..." }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +require("lazy").setup({ + spec = { + -- add LazyVim and import its plugins + { "LazyVim/LazyVim", import = "lazyvim.plugins" }, + -- import/override with your plugins + { import = "plugins" }, + }, + defaults = { + -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup. + -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default. + lazy = false, + -- It's recommended to leave version=false for now, since a lot the plugin that support versioning, + -- have outdated releases, which may break your Neovim install. + version = false, -- always use the latest git commit + -- version = "*", -- try installing the latest stable version for plugins that support semver + }, + install = { colorscheme = { "tokyonight", "habamax" } }, + checker = { + enabled = true, -- check for plugin updates periodically + notify = false, -- notify on update + }, -- automatically check for plugin updates + performance = { + rtp = { + -- disable some rtp plugins + disabled_plugins = { + "gzip", + -- "matchit", + -- "matchparen", + -- "netrwPlugin", + "tarPlugin", + "tohtml", + "tutor", + "zipPlugin", + }, + }, + }, +}) diff --git a/.config/nvim/lua/config/options.lua b/.config/nvim/lua/config/options.lua new file mode 100644 index 0000000..195b7fe --- /dev/null +++ b/.config/nvim/lua/config/options.lua @@ -0,0 +1,6 @@ +-- Options are automatically loaded before lazy.nvim startup +-- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua +-- Add any additional options here + +-- Enable transparency support for iTerm2 +vim.opt.termguicolors = true diff --git a/.config/nvim/lua/plugins/example.lua b/.config/nvim/lua/plugins/example.lua new file mode 100644 index 0000000..17f53d6 --- /dev/null +++ b/.config/nvim/lua/plugins/example.lua @@ -0,0 +1,197 @@ +-- since this is just an example spec, don't actually load anything here and return an empty spec +-- stylua: ignore +if true then return {} end + +-- every spec file under the "plugins" directory will be loaded automatically by lazy.nvim +-- +-- In your plugin files, you can: +-- * add extra plugins +-- * disable/enabled LazyVim plugins +-- * override the configuration of LazyVim plugins +return { + -- add gruvbox + { "ellisonleao/gruvbox.nvim" }, + + -- Configure LazyVim to load gruvbox + { + "LazyVim/LazyVim", + opts = { + colorscheme = "gruvbox", + }, + }, + + -- change trouble config + { + "folke/trouble.nvim", + -- opts will be merged with the parent spec + opts = { use_diagnostic_signs = true }, + }, + + -- disable trouble + { "folke/trouble.nvim", enabled = false }, + + -- override nvim-cmp and add cmp-emoji + { + "hrsh7th/nvim-cmp", + dependencies = { "hrsh7th/cmp-emoji" }, + ---@param opts cmp.ConfigSchema + opts = function(_, opts) + table.insert(opts.sources, { name = "emoji" }) + end, + }, + + -- change some telescope options and a keymap to browse plugin files + { + "nvim-telescope/telescope.nvim", + keys = { + -- add a keymap to browse plugin files + -- stylua: ignore + { + "<leader>fp", + function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end, + desc = "Find Plugin File", + }, + }, + -- change some options + opts = { + defaults = { + layout_strategy = "horizontal", + layout_config = { prompt_position = "top" }, + sorting_strategy = "ascending", + winblend = 0, + }, + }, + }, + + -- add pyright to lspconfig + { + "neovim/nvim-lspconfig", + ---@class PluginLspOpts + opts = { + ---@type lspconfig.options + servers = { + -- pyright will be automatically installed with mason and loaded with lspconfig + pyright = {}, + }, + }, + }, + + -- add tsserver and setup with typescript.nvim instead of lspconfig + { + "neovim/nvim-lspconfig", + dependencies = { + "jose-elias-alvarez/typescript.nvim", + init = function() + require("lazyvim.util").lsp.on_attach(function(_, buffer) + -- stylua: ignore + vim.keymap.set( "n", "<leader>co", "TypescriptOrganizeImports", { buffer = buffer, desc = "Organize Imports" }) + vim.keymap.set("n", "<leader>cR", "TypescriptRenameFile", { desc = "Rename File", buffer = buffer }) + end) + end, + }, + ---@class PluginLspOpts + opts = { + ---@type lspconfig.options + servers = { + -- tsserver will be automatically installed with mason and loaded with lspconfig + tsserver = {}, + }, + -- you can do any additional lsp server setup here + -- return true if you don't want this server to be setup with lspconfig + ---@type table<string, fun(server:string, opts:_.lspconfig.options):boolean?> + setup = { + -- example to setup with typescript.nvim + tsserver = function(_, opts) + require("typescript").setup({ server = opts }) + return true + end, + -- Specify * to use this function as a fallback for any server + -- ["*"] = function(server, opts) end, + }, + }, + }, + + -- for typescript, LazyVim also includes extra specs to properly setup lspconfig, + -- treesitter, mason and typescript.nvim. So instead of the above, you can use: + { import = "lazyvim.plugins.extras.lang.typescript" }, + + -- add more treesitter parsers + { + "nvim-treesitter/nvim-treesitter", + opts = { + ensure_installed = { + "bash", + "html", + "javascript", + "json", + "lua", + "markdown", + "markdown_inline", + "python", + "query", + "regex", + "tsx", + "typescript", + "vim", + "yaml", + }, + }, + }, + + -- since `vim.tbl_deep_extend`, can only merge tables and not lists, the code above + -- would overwrite `ensure_installed` with the new value. + -- If you'd rather extend the default config, use the code below instead: + { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + -- add tsx and treesitter + vim.list_extend(opts.ensure_installed, { + "tsx", + "typescript", + }) + end, + }, + + -- the opts function can also be used to change the default opts: + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = function(_, opts) + table.insert(opts.sections.lualine_x, { + function() + return "😄" + end, + }) + end, + }, + + -- or you can return new options to override all the defaults + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = function() + return { + --[[add your custom lualine config here]] + } + end, + }, + + -- use mini.starter instead of alpha + { import = "lazyvim.plugins.extras.ui.mini-starter" }, + + -- add jsonls and schemastore packages, and setup treesitter for json, json5 and jsonc + { import = "lazyvim.plugins.extras.lang.json" }, + + -- add any tools you want to have installed below + { + "williamboman/mason.nvim", + opts = { + ensure_installed = { + "stylua", + "shellcheck", + "shfmt", + "flake8", + }, + }, + }, +} diff --git a/.config/nvim/lua/plugins/lushwal.lua b/.config/nvim/lua/plugins/lushwal.lua new file mode 100644 index 0000000..94c5681 --- /dev/null +++ b/.config/nvim/lua/plugins/lushwal.lua @@ -0,0 +1,119 @@ +local function apply_transparent_overrides() + local hl = vim.api.nvim_set_hl + local none = "NONE" + hl(0, "Normal", { bg = none }) + hl(0, "NormalFloat", { bg = none }) + hl(0, "FloatBorder", { bg = none }) + hl(0, "EndOfBuffer", { bg = none }) + hl(0, "CursorLine", { bg = none }) + hl(0, "LineNr", { bg = none }) + hl(0, "SignColumn", { bg = none }) + hl(0, "Pmenu", { bg = none }) + hl(0, "PmenuSel", { bg = none }) + hl(0, "TelescopeNormal", { bg = none }) + hl(0, "TelescopeBorder", { bg = none }) +end + +local function set_transparent(on) + vim.g.lushwal_transparent = on + if on then + apply_transparent_overrides() + else + -- Restore theme defaults (pywal colors with solid background) + vim.cmd("colorscheme lushwal") + end + vim.notify( + (on and "Transparency on" or "Transparency off"), + vim.log.levels.INFO, + { title = "Lushwal" } + ) +end + +local function toggle_transparent() + set_transparent(vim.g.lushwal_transparent ~= true) +end + +return { + { + "oncomouse/lushwal.nvim", + cmd = { "LushwalCompile" }, + dependencies = { + { "rktjmp/lush.nvim" }, + { "rktjmp/shipwright.nvim" }, + }, + lazy = false, + init = function() + -- Solid background by default (pywal colors). Run :LushwalCompile once after this change to regenerate the theme. + vim.g.lushwal_configuration = { + transparent_background = false, + } + end, + config = function() + vim.g.lushwal_transparent = false -- off by default + vim.api.nvim_create_user_command("LushwalToggleTransparency", toggle_transparent, {}) + vim.keymap.set("n", "<leader>ut", toggle_transparent, { desc = "Toggle transparency" }) + -- Re-apply transparent overrides after colorscheme load when user had transparency on + vim.api.nvim_create_autocmd("ColorScheme", { + pattern = "lushwal", + callback = function() + if vim.g.lushwal_transparent then + apply_transparent_overrides() + else + -- Softer cursor line so the active line doesn't overpower the text + vim.api.nvim_set_hl(0, "CursorLine", { bg = "#252530", fg = "NONE" }) + end + end, + }) + -- Apply subtle CursorLine on first load (non-transparent default) + vim.defer_fn(function() + if vim.g.colors_name == "lushwal" and not vim.g.lushwal_transparent then + vim.api.nvim_set_hl(0, "CursorLine", { bg = "#252530", fg = "NONE" }) + end + end, 10) + end, + }, + -- Add project.nvim for better project management + { + "ahmedkhalf/project.nvim", + keys = { + { "<leader>fp", "<Cmd>Telescope projects<CR>", desc = "Find Projects" }, + }, + config = function() + require("project_nvim").setup({ + -- Path where to store the project history for telescope + datapath = vim.fn.stdpath("data"), + -- Detection methods for projects + detection_methods = { "pattern", "lsp" }, + -- Patterns used to detect projects + patterns = { + ".git", + "_darcs", + ".hg", + ".bzr", + ".svn", + "Makefile", + "package.json", + "Cargo.toml", + "requirements.txt", + "pyproject.toml", + "go.mod", + "composer.json", + "Gemfile", + ".lazy.lua", + }, + -- Only consider these directories as projects + scope_chdir = "tab", + -- What to do when changing project + silent_chdir = false, + }) + require("telescope").load_extension("projects") + end, + }, + -- Configure LazyVim to load lushwal + { + "LazyVim/LazyVim", + opts = { + colorscheme = "lushwal", + }, + }, +} diff --git a/.config/nvim/stylua.toml b/.config/nvim/stylua.toml new file mode 100644 index 0000000..0f90030 --- /dev/null +++ b/.config/nvim/stylua.toml @@ -0,0 +1,3 @@ +indent_type = "Spaces" +indent_width = 2 +column_width = 120 diff --git a/.config/tmux-powerline/config.sh b/.config/tmux-powerline/config.sh new file mode 100644 index 0000000..14498ef --- /dev/null +++ b/.config/tmux-powerline/config.sh @@ -0,0 +1,469 @@ +# Default configuration file for tmux-powerline. +# Modeline { +# vi: foldmarker={,} foldmethod=marker foldlevel=0 tabstop=4 filetype=sh +# } + +# General { +# Show which segment fails and its exit code. +export TMUX_POWERLINE_DEBUG_MODE_ENABLED="false" +# Create error log in tmux runtime temp dir. +export TMUX_POWERLINE_ERROR_LOGS_ENABLED="false" +# Only log specific scopes. Space separated list of scopes. Supported scopes: weather.sh lib/text_roll.sh lib/powerline.sh lib/colors.sh config/helpers.sh +export TMUX_POWERLINE_ERROR_LOGS_SCOPES="" +# Use patched font symbols. +export TMUX_POWERLINE_PATCHED_FONT_IN_USE="true" + +# The theme to use. +export TMUX_POWERLINE_THEME="main" +# Overlay directory to look for themes. There you can put your own themes outside the repo. Fallback will still be the "themes" directory in the repo. +export TMUX_POWERLINE_DIR_USER_THEMES="${XDG_CONFIG_HOME:-$HOME/.config}/tmux-powerline/themes" +# Overlay directory to look for segments. There you can put your own segments outside the repo. Fallback will still be the "segments" directory in the repo. +export TMUX_POWERLINE_DIR_USER_SEGMENTS="${XDG_CONFIG_HOME:-$HOME/.config}/tmux-powerline/segments" + +# The initial visibility of the status bar. Can be {"on", "off", "2"}. 2 will create two status lines: one for the window list and one with status bar segments. +export TMUX_POWERLINE_STATUS_VISIBILITY="on" +# In case of visibility = 2, where to display window status and where left/right status bars. +# 0: window status top, left/right status bottom; 1: window status bottom, left/right status top +export TMUX_POWERLINE_WINDOW_STATUS_LINE=0 +# The status bar refresh interval in seconds. +# Note that events that force-refresh the status bar (such as window renaming) will ignore this. +export TMUX_POWERLINE_STATUS_INTERVAL="1" +# The location of the window list. Can be {"absolute-centre, centre, left, right"}. +# Note that "absolute-centre" is only supported on `tmux -V` >= 3.2. +export TMUX_POWERLINE_STATUS_JUSTIFICATION="left" + +# The maximum length of the left status bar. +export TMUX_POWERLINE_STATUS_LEFT_LENGTH="60" +# The maximum length of the right status bar. +export TMUX_POWERLINE_STATUS_RIGHT_LENGTH="90" + +# The separator to use between windows on the status bar. +export TMUX_POWERLINE_WINDOW_STATUS_SEPARATOR="" + +# Uncomment these if you want to enable tmux bindings for muting (hiding) one of the status bars. +# E.g. this example binding would mute the left status bar when pressing <prefix> followed by Ctrl-[ +#export TMUX_POWERLINE_MUTE_LEFT_KEYBINDING="C-[" +#export TMUX_POWERLINE_MUTE_RIGHT_KEYBINDING="C-]" +# } + +# air.sh { +# The data provider to use. Currently only "openweather" is supported. +export TMUX_POWERLINE_SEG_AIR_DATA_PROVIDER="openweather" +# How often to update the weather in seconds. +export TMUX_POWERLINE_SEG_AIR_UPDATE_PERIOD="600" +# Location of the JSON parser, jq +export TMUX_POWERLINE_SEG_AIR_JSON="jq" +# Your location +# Latitude and Longitude: +TMUX_POWERLINE_SEG_AIR_LAT="" +TMUX_POWERLINE_SEG_AIR_LON="" +# Your Open Weather API Key: +TMUX_POWERLINE_SEG_AIR_OPEN_WEATHER_API_KEY="" +# } + +# battery.sh { +# How to display battery remaining. Can be {percentage, cute, hearts}. +export TMUX_POWERLINE_SEG_BATTERY_TYPE="percentage" +# How may hearts to show if cute indicators are used. +export TMUX_POWERLINE_SEG_BATTERY_NUM_HEARTS="5" +# } + +# cpu_temp.sh { +# CPU temperature icon +export TMUX_POWERLINE_SEG_CPU_TEMP_ICON=" " +# Linux only. Regexp to indicate a line containing CPU temperature in 'sensors' output. +# Check the output of 'sensors' program, decide which line contains desired CPU temperature +# and store an unique part of that line in this variable. It will be used by 'grep' program +# to distinct the 'CPU temperature' line from the rest output lines. +export TMUX_POWERLINE_SEG_CPU_TEMP_SENSORS_LINE_MARKER="Package id 0\|Physical id 0\|temp1" +# } + +# date_week.sh { +# Symbol for calendar week. +# export TMUX_POWERLINE_SEG_DATE_WEEK_SYMBOL="" +# export TMUX_POWERLINE_SEG_DATE_WEEK_SYMBOL_COLOUR="255" +# } + +# date.sh { +# date(1) format for the date. If you don't, for some reason, like ISO 8601 format you might want to have "%D" or "%m/%d/%Y". +export TMUX_POWERLINE_SEG_DATE_FORMAT="%F" +# } + +# disk_usage.sh { +# Filesystem to retrieve disk space information. Any from the filesystems available (run "df | awk '{print }'" to check them). +export TMUX_POWERLINE_SEG_DISK_USAGE_FILESYSTEM="/" +# } + +# dropbox_status.sh { +# The Dropbox glyph to use +export TMUX_POWERLINE_SEG_DROPBOX_GLYPH="\uf16b" +# Replace 'Uploading' in the status +export TMUX_POWERLINE_SEG_DROPBOX_UPLOAD_GLYPH="\uf093" +# Replace 'Downloading' in the status +export TMUX_POWERLINE_SEG_DROPBOX_DOWNLOAD_GLYPH="\uf019" +# Replace 'Indexing' in the status +export TMUX_POWERLINE_SEG_DROPBOX_INDEX_GLYPH="\uf02e" +# Replace 'Syncing' in the status +export TMUX_POWERLINE_SEG_DROPBOX_SYNC_GLYPH="\uf46a" +# } + +# earthquake.sh { +# The data provider to use. Currently only "goo" is supported. +export TMUX_POWERLINE_SEG_EARTHQUAKE_DATA_PROVIDER="goo" +# How often to update the earthquake data in seconds. +# Note: This is not an early warning detector, use this +# to be informed about recent earthquake magnitudes in your +# area. If this is too often, goo may decide to ban you form +# their server +export TMUX_POWERLINE_SEG_EARTHQUAKE_UPDATE_PERIOD="600" +# Only display information when earthquakes are within this many minutes +export TMUX_POWERLINE_SEG_EARTHQUAKE_ALERT_TIME_WINDOW="60" +# Display time with this format +export TMUX_POWERLINE_SEG_EARTHQUAKE_TIME_FORMAT='(%H:%M)' +# Display only if magnitude is greater or equal to this number +export TMUX_POWERLINE_SEG_EARTHQUAKE_MIN_MAGNITUDE="3" +# } + +# gcalcli.sh { +# gcalcli uses 24hr time format by default - if you want to see 12hr time format, set TMUX_POWERLINE_SEG_GCALCLI_MILITARY_TIME_DEFAULT to 0 +export TMUX_POWERLINE_SEG_GCALCLI_24HR_TIME_FORMAT="1" +# } + +# github_notifications.sh { +# Github token (https://github.com/settings/tokens) with at least "notifications" scope +export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_TOKEN="" +# Include available notification reasons (https://docs.github.com/en/rest/activity/notifications?apiVersion=2022-11-28#about-notification-reasons), +# in the format "REASON:SEPARATOR" +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_REASONS="approval_requested:- |assign:- |author:- |comment:- |ci_activity:- |invitation:- |manual:- |mention:- |review_requested:- |security_alert:- |state_change:- |subscribed:- |team_mention:- " +# Or if you don't like so many symbols, try the abbreviation variant +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_REASONS="approval_requested:areq|assign:as|author:au|comment:co|ci_activity:ci|invitation:in|manual:ma|mention:me|review_requested:rreq|security_alert:sec|state_change:st|subscribed:sub|team_mention:team" +# Use symbol mode (ignored if you set TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_REASONS yourself) +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_SYMBOL_MODE="yes" +# Summarize all notifications +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_SUMMARIZE="no" +# Hide if no notifications +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_HIDE_NO_NOTIFICATIONS="yes" +# Only show new notifications since date (default: today) (takes up to UPDATE_INTERVAL time to take effect) +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_SINCE="$(date +%Y-%m-%dT00:00:00Z)" +# Enable show only notifications since date (takes up to UPDATE_INTERVAL time to take effect) +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_SINCE_ENABLE="no" +# Maximum notifications to retreive per page (upstream github default per_page, 50) +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_PER_PAGE="50" +# Maximum pages to retreive +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_MAX_PAGES="10" +# Update interval to pull latest state from github api +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_UPDATE_INTERVAL="60" +# Enable Test Mode (to test how the segment will look like when you have notifications for all types/reasons) +# export TMUX_POWERLINE_SEG_GITHUB_NOTIFICATIONS_TEST_MODE="no" +# } + +# hostname.sh { +# Use short, long or custom format for the hostname. Can be {"short", "long", "custom"}. +export TMUX_POWERLINE_SEG_HOSTNAME_FORMAT="short" +# Custom name to be used when format is "custom" +export TMUX_POWERLINE_SEG_HOSTNAME_CUSTOM="" +# } + +# ifstat.sh { +# Symbol for Download. +# export TMUX_POWERLINE_SEG_IFSTAT_DOWN_SYMBOL="⇊" +# Symbol for Upload. +# export TMUX_POWERLINE_SEG_IFSTAT_UP_SYMBOL="⇈" +# Symbol for Ethernet. +# export TMUX_POWERLINE_SEG_IFSTAT_ETHERNET_SYMBOL="" +# Symbol for WLAN. +# export TMUX_POWERLINE_SEG_IFSTAT_WLAN_SYMBOL="" +# Symbol for WWAN. +# export TMUX_POWERLINE_SEG_IFSTAT_WWAN_SYMBOL="" +# Separator for Interfaces. +# export TMUX_POWERLINE_SEG_IFSTAT_INTERFACE_SEPARATOR=" | " +# Space separated list of interface names to be excluded. substring match, regexp can be used. +# Examples: +# export TMUX_POWERLINE_SEG_IFSTAT_INTERFACE_EXCLUDES="tun" # will exclude 'tun0', 'utun0', 'itun', 'tun08127387' +# export TMUX_POWERLINE_SEG_IFSTAT_INTERFACE_EXCLUDES="tun0 tuntun" # will exclude 'tun0', 'utun0', 'tuntun' +# export TMUX_POWERLINE_SEG_IFSTAT_INTERFACE_EXCLUDES="^tun0$ ^tun1$" # excludes exactly 'tun0' and 'tun1' +# Default: +# export TMUX_POWERLINE_SEG_IFSTAT_INTERFACE_EXCLUDES="^u?tun[0-9]+$" +# } + +# kubernetes_context.sh { +# Kubernetes config context display mode {"name_namespace", "name", "namespace"}. +# export TMUX_POWERLINE_SEG_KUBERNETES_CONTEXT_DISPLAY_MODE="name_namespace" +# Kubernetes config context symbol. +# export TMUX_POWERLINE_SEG_KUBERNETES_CONTEXT_SYMBOL="" +# Kubernetes config context symbol colour. +# export TMUX_POWERLINE_SEG_KUBERNETES_CONTEXT_SYMBOL_COLOUR="255" +# Separator for display mode "name_namespace" +# TMUX_POWERLINE_SEG_KUBERNETES_CONTEXT_SEPARATOR="" +# } + +# lan_ip.sh { +# Symbol for LAN IP. +# export TMUX_POWERLINE_SEG_LAN_IP_SYMBOL="ⓛ " +# Symbol colour for LAN IP +# export TMUX_POWERLINE_SEG_LAN_IP_SYMBOL_COLOUR="255" +# } + +# macos_notification_count.sh { + +# } + +# mailcount.sh { +# Mailbox type to use. Can be any of {apple_mail, gmail, maildir, mbox, mailcheck} +export TMUX_POWERLINE_SEG_MAILCOUNT_MAILBOX_TYPE="" + +## Gmail +# Enter your Gmail username here WITH OUT @gmail.com.( OR @domain) +export TMUX_POWERLINE_SEG_MAILCOUNT_GMAIL_USERNAME="" +# Google password. Recomenned to use application specific password (https://accounts.google.com/b/0/IssuedAuthSubTokens) Leave this empty to get password from OS X keychain. +# For macOS users : MAKE SURE that you add a key to the keychain in the format as follows +# Keychain Item name : http://<value-you-fill-in-server-variable-below> +# Account name : <username-below>@<server-below> +# Password : Your password ( Once again, try to use 2 step-verification and application-specific password) +# See http://support.google.com/accounts/bin/answer.py?hl=en&answer=185833 for more info. +export TMUX_POWERLINE_SEG_MAILCOUNT_GMAIL_PASSWORD="" +# Domain name that will complete your email. For normal GMail users it probably is "gmail.com but can be "foo.tld" for Google Apps users. +export TMUX_POWERLINE_SEG_MAILCOUNT_GMAIL_SERVER="gmail.com" +# How often in minutes to check for new mails. +export TMUX_POWERLINE_SEG_MAILCOUNT_GMAIL_INTERVAL="5" + +## Maildir +# Path to the maildir to check. +export TMUX_POWERLINE_SEG_MAILCOUNT_MAILDIR_INBOX="$HOME/.mail/inbox/new" + +## mbox +# Path to the mbox to check. +export TMUX_POWERLINE_SEG_MAILCOUNT_MBOX_INBOX="" + +## mailcheck +# Optional path to mailcheckrc +export TMUX_POWERLINE_SEG_MAILCOUNT_MAILCHECKRC="$HOME/.mailcheckrc" +# } + +# mode_indicator.sh { +# Whether the normal & prefix mode section should be enabled. Should be {"true, "false"}. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_NORMAL_AND_PREFIX_MODE_ENABLED="true" +# Normal mode text & color overrides. Defaults to "normal" & the segment foreground color set in the theme used. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_NORMAL_MODE_TEXT="normal" +export TMUX_POWERLINE_SEG_MODE_INDICATOR_NORMAL_MODE_TEXT_COLOR="" +# Prefix mode text & color overrides. Defaults to "prefix" & the segment foreground color set in the theme used. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_PREFIX_MODE_TEXT="prefix" +export TMUX_POWERLINE_SEG_MODE_INDICATOR_PREFIX_MODE_TEXT_COLOR="" +# Whether the mouse mode section should be enabled. Should be {"true, "false"}. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_MOUSE_MODE_ENABLED="true" +# Mouse mode text & color overrides. Defaults to "mouse" & the segment foreground color set in the theme used. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_MOUSE_MODE_TEXT="mouse" +export TMUX_POWERLINE_SEG_MODE_INDICATOR_MOUSE_MODE_TEXT_COLOR="" +# Whether the copy mode section should be enabled. Should be {"true, "false"}. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_COPY_MODE_ENABLED="true" +# Copy mode text & color overrides. Defaults to "copy" & the segment foreground color set in the theme used. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_COPY_MODE_TEXT="copy" +export TMUX_POWERLINE_SEG_MODE_INDICATOR_COPY_MODE_TEXT_COLOR="" +# Suspend mode text & color overrides. Defaults to "SUSPEND" & the segment foreground color set in the theme used. +export TMUX_POWERLINE_SEG_MODE_INDICATOR_SUSPEND_MODE_TEXT="SUSPEND" +export TMUX_POWERLINE_SEG_MODE_INDICATOR_SUSPEND_MODE_TEXT_COLOR="" +# Separator text override. Defaults to " • ". +export TMUX_POWERLINE_SEG_MODE_INDICATOR_SEPARATOR_TEXT=" • " +# } + +# now_playing.sh { +# Music player to use. Can be any of {audacious, banshee, cmus, apple_music, itunes, lastfm, plexamp, mocp, mpd, mpd_simple, pithos, playerctl, rdio, rhythmbox, spotify, file}. +export TMUX_POWERLINE_SEG_NOW_PLAYING_MUSIC_PLAYER="lastfm" +# File to be read in case the song is being read from a file +export TMUX_POWERLINE_SEG_NOW_PLAYING_FILE_NAME="" +# Maximum output length. +export TMUX_POWERLINE_SEG_NOW_PLAYING_MAX_LEN="40" +# How to handle too long strings. Can be {trim, roll}. +export TMUX_POWERLINE_SEG_NOW_PLAYING_TRIM_METHOD="trim" +# Characters per second to roll if rolling trim method is used. +export TMUX_POWERLINE_SEG_NOW_PLAYING_ROLL_SPEED="2" +# Mode of roll text {"space", "repeat"}. space: fill up with empty space; repeat: repeat text from beginning +# export TMUX_POWERLINE_SEG_NOW_PLAYING_ROLL_MODE="repeat" +# Separator for "repeat" roll mode +# export TMUX_POWERLINE_SEG_NOW_PLAYING_ROLL_SEPARATOR=" " +# If set to 'true', 'yes', 'on' or '1', played tracks will be logged to a file. +# export TMUX_POWERLINE_SEG_NOW_PLAYING_TRACK_LOG_ENABLE="false" +# If enabled, log played tracks to the following file: +# export TMUX_POWERLINE_SEG_NOW_PLAYING_TRACK_LOG_FILEPATH="$HOME/.now_playing.log" +# Maximum number of logged song entries. Set to "unlimited" for unlimited entries. +# export TMUX_POWERLINE_SEG_NOW_PLAYING_TRACK_LOG_MAX_ENTRIES="100" + +# Hostname for MPD server in the format "[password@]host" +export TMUX_POWERLINE_SEG_NOW_PLAYING_MPD_HOST="localhost" +# Port the MPD server is running on. +export TMUX_POWERLINE_SEG_NOW_PLAYING_MPD_PORT="6600" +# Song display format for mpd_simple. See mpc(1) for delimiters. +export TMUX_POWERLINE_SEG_NOW_PLAYING_MPD_SIMPLE_FORMAT="%artist% - %title%" +# Song display format for playerctl. see "Format Strings" in playerctl(1). +export TMUX_POWERLINE_SEG_NOW_PLAYING_PLAYERCTL_FORMAT="{{ artist }} - {{ title }}" +# Song display format for rhythmbox. see "FORMATS" in rhythmbox-client(1). +export TMUX_POWERLINE_SEG_NOW_PLAYING_RHYTHMBOX_FORMAT="%aa - %tt" + +# Last.fm +# Set up steps for Last.fm +# 1. Make sure jq(1) is installed on the system. +# 2. Create a new API application at https://www.last.fm/api/account/create (name it tmux-powerline) and copy the API key and insert it below in the setting TMUX_POWERLINE_SEG_NOW_PLAYING_LASTFM_API_KEY +# 3. Make sure the API can access your recently played song by going to you user privacy settings https://www.last.fm/settings/privacy and make sure "Hide recent listening information" is UNCHECKED. +# Username for Last.fm if that music player is used. +export TMUX_POWERLINE_SEG_NOW_PLAYING_LASTFM_USERNAME="" +# API Key for the API. +export TMUX_POWERLINE_SEG_NOW_PLAYING_LASTFM_API_KEY="" +# How often in seconds to update the data from last.fm. +export TMUX_POWERLINE_SEG_NOW_PLAYING_LASTFM_UPDATE_PERIOD="30" +# Fancy char to display before now playing track +export TMUX_POWERLINE_SEG_NOW_PLAYING_NOTE_CHAR="♫" + +# Plexamp +# Set up steps for Plexamp +# 1. Make sure jq(1) is installed on the system. +# 2. Make sure you have an instance of Tautulli that is accessible by the computer running tmux-powerline. +# Username for Plexamp if that music player is used. +export TMUX_POWERLINE_SEG_NOW_PLAYING_PLEXAMP_USERNAME="" +# Hostname for Tautulli server in the format "[password@]host" +export TMUX_POWERLINE_SEG_NOW_PLAYING_PLEXAMP_TAUTULLI_HOST="" +# API Key for Tautulli. +export TMUX_POWERLINE_SEG_NOW_PLAYING_PLEXAMP_TAUTULLI_API_KEY="" +# How often in seconds to update the data from Plexamp. +export TMUX_POWERLINE_SEG_NOW_PLAYING_PLEXAMP_UPDATE_PERIOD="30" +# } + +# pwd.sh { +# Maximum length of output. +export TMUX_POWERLINE_SEG_PWD_MAX_LEN="40" +# } + +# time.sh { +# date(1) format for the time. Americans might want to have "%I:%M %p". +export TMUX_POWERLINE_SEG_TIME_FORMAT="%H:%M" +# Change this to display a different timezone than the system default. +# Use TZ Identifier like "America/Los_Angeles" +# export TMUX_POWERLINE_SEG_TIME_TZ="" +# } + +# tmux_continuum_save.sh { +# Path to the tmux-continuum git repo. +export TMUX_POWERLINE_SEG_TMUX_CONTINUUM_PATH="$HOME/.tmux/plugins/tmux-continuum" +# } + +# tmux_continuum_status.sh { +# Path to the tmux-continuum git repo. +export TMUX_POWERLINE_SEG_TMUX_CONTINUUM_PATH="$HOME/.tmux/plugins/tmux-continuum" +# Message to perfix the status indication with. +export TMUX_POWERLINE_SEG_TMUX_CONTINUUM_PREFIX="Continuum status: " +# } + +# tmux_mem_cpu_load.sh { +# Arguments passed to tmux-mem-cpu-load. +# See https://github.com/thewtex/tmux-mem-cpu-load for all available options. +# export TMUX_POWERLINE_SEG_TMUX_MEM_CPU_LOAD_ARGS="-v" +# } + +# tmux_session_info.sh { +# Session info format to feed into the command: tmux display-message -p +# For example, if FORMAT is '[ #S ]', the command is: tmux display-message -p '[ #S ]' +export TMUX_POWERLINE_SEG_TMUX_SESSION_INFO_FORMAT="#S:#I.#P" +# } + +# utc_time.sh { +# date(1) format for the UTC time. +export TMUX_POWERLINE_SEG_UTC_TIME_FORMAT="%H:%M %Z" +# } + +# vcs_branch.sh { +# Max length of the branch name. +export TMUX_POWERLINE_SEG_VCS_BRANCH_MAX_LEN="" +# Symbol when branch length exceeds max length +# export TMUX_POWERLINE_SEG_VCS_BRANCH_TRUNCATE_SYMBOL="…" +# Default branch symbol +export TMUX_POWERLINE_SEG_VCS_BRANCH_DEFAULT_SYMBOL="" +# Branch symbol for git repositories +# export TMUX_POWERLINE_SEG_VCS_BRANCH_GIT_SYMBOL="${TMUX_POWERLINE_SEG_VCS_BRANCH_DEFAULT_SYMBOL}" +# Branch symbol for hg/mercurial repositories +# export TMUX_POWERLINE_SEG_VCS_BRANCH_HG_SYMBOL="${TMUX_POWERLINE_SEG_VCS_BRANCH_DEFAULT_SYMBOL}" +# Branch symbol for SVN repositories +# export TMUX_POWERLINE_SEG_VCS_BRANCH_SVN_SYMBOL="${TMUX_POWERLINE_SEG_VCS_BRANCH_DEFAULT_SYMBOL}" +# Branch symbol colour for git repositories +export TMUX_POWERLINE_SEG_VCS_BRANCH_GIT_SYMBOL_COLOUR="5" +# Branch symbol colour for hg/mercurial repositories +export TMUX_POWERLINE_SEG_VCS_BRANCH_HG_SYMBOL_COLOUR="45" +# Branch symbol colour for SVN repositories +export TMUX_POWERLINE_SEG_VCS_BRANCH_SVN_SYMBOL_COLOUR="220" +# } + +# vcs_compare.sh { +# Symbol if local branch is behind. +# export TMUX_POWERLINE_SEG_VCS_COMPARE_AHEAD_SYMBOL="↑ " +# Symbol colour if local branch is ahead. Defaults to "current segment foreground colour" +# export TMUX_POWERLINE_SEG_VCS_COMPARE_AHEAD_SYMBOL_COLOUR="" +# Symbol if local branch is ahead. +# export TMUX_POWERLINE_SEG_VCS_COMPARE_BEHIND_SYMBOL="↓ " +# Symbol colour if local branch is behind. Defaults to "current segment foreground colour" +# export TMUX_POWERLINE_SEG_VCS_COMPARE_BEHIND_SYMBOL_COLOUR="" +# } + +# vcs_modified.sh { +# Symbol for count of modified vcs files. +# export TMUX_POWERLINE_SEG_VCS_MODIFIED_SYMBOL="± " +# } + +# vcs_others.sh { +# Symbol for count of untracked vcs files. +# export TMUX_POWERLINE_SEG_VCS_OTHERS_SYMBOL="⋯" +# } + +# vcs_rootpath.sh { +# Display mode for vcs_rootpath. +# Example: (name: folder name only; path: full path, w/o expansion; user_path: full path, w/ tilde expansion) +# export TMUX_POWERLINE_SEG_VCS_ROOTPATH_MODE="name" +# } + +# vcs_staged.sh { +# Symbol for count of staged vcs files. +# export TMUX_POWERLINE_SEG_VCS_STAGED_SYMBOL="⊕ " +# } + +# vpn.sh { +# Mode for VPN segment {"both", "ip", "name"}. both: Show NIC/IP; ip: Show only IP; name: Show only NIC name +# export TMUX_POWERLINE_SEG_VPN_DISPLAY_MODE="both" +# Space separated list of tunnel interface names. First match is being used. substring match, regexp can be used. +# Examples: +# export TMUX_POWERLINE_SEG_VPN_NICS="tun" # will match 'tun0', 'utun0', 'itun', 'tun08127387' +# export TMUX_POWERLINE_SEG_VPN_NICS="tun0 tuntun" # will match 'tun0', 'utun0', 'tuntun' +# export TMUX_POWERLINE_SEG_VPN_NICS="^tun0$ ^tun1$" # exactly 'tun0' and 'tun1' +# Default: +# export TMUX_POWERLINE_SEG_VPN_NICS='^u?tun[0-9]+$' +# Symbol to use for vpn tunnel. +# export TMUX_POWERLINE_SEG_VPN_SYMBOL=" " +# Colour for vpn tunnel symbol +# export TMUX_POWERLINE_SEG_VPN_SYMBOL_COLOUR="255" +# Symbol for separator +# export TMUX_POWERLINE_SEG_VPN_DISPLAY_SEPARATOR="" +# } + +# wan_ip.sh { +# Symbol for WAN IP +# export TMUX_POWERLINE_SEG_WAN_IP_SYMBOL="ⓦ " +# Symbol colour for WAN IP +# export TMUX_POWERLINE_SEG_WAN_IP_SYMBOL_COLOUR="255" +# } + +# weather.sh { +# The data provider to use. Currently only "yrno" is supported. +export TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER="yrno" +# What unit to use. Can be any of {c,f,k}. +export TMUX_POWERLINE_SEG_WEATHER_UNIT="c" +# How often to update the weather in seconds. +export TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD="600" +# How often to update the weather location in seconds (this is only used when latitude and longitude settings are set to "auto") +export TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD="86400" +# Your location +# Latitude and Longtitude for use with yr.no +# Set both to "auto" to detect automatically based on your IP address, or set them manually +export TMUX_POWERLINE_SEG_WEATHER_LAT="auto" +export TMUX_POWERLINE_SEG_WEATHER_LON="auto" +# } + +# xkb_layout.sh { +# Keyboard icon +export TMUX_POWERLINE_SEG_XKB_LAYOUT_ICON="⌨ " +# } diff --git a/.config/tmux-powerline/themes/main.sh b/.config/tmux-powerline/themes/main.sh new file mode 100644 index 0000000..c558c2b --- /dev/null +++ b/.config/tmux-powerline/themes/main.sh @@ -0,0 +1,230 @@ +# shellcheck shell=bash +# Pywal Theme - Integrated with pywal colors +# If changes made here does not take effect, then try to re-create the tmux session to force reload. + +# Source pywal colors if available +if [ -f "${HOME}/.cache/wal/colors.sh" ]; then + # shellcheck source=/dev/null + source "${HOME}/.cache/wal/colors.sh" +fi + +if tp_patched_font_in_use; then + TMUX_POWERLINE_SEPARATOR_LEFT_BOLD="" + TMUX_POWERLINE_SEPARATOR_LEFT_THIN="" + TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD="" + TMUX_POWERLINE_SEPARATOR_RIGHT_THIN="" +else + TMUX_POWERLINE_SEPARATOR_LEFT_BOLD="◀" + TMUX_POWERLINE_SEPARATOR_LEFT_THIN="❮" + TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD="▶" + TMUX_POWERLINE_SEPARATOR_RIGHT_THIN="❯" +fi + +# See Color formatting section below for details on what colors can be used here. +# Use pywal colors if available, otherwise fallback to defaults +if [ -n "$background" ] && [ -n "$foreground" ]; then + TMUX_POWERLINE_DEFAULT_BACKGROUND_COLOR=${TMUX_POWERLINE_DEFAULT_BACKGROUND_COLOR:-"$background"} + TMUX_POWERLINE_DEFAULT_FOREGROUND_COLOR=${TMUX_POWERLINE_DEFAULT_FOREGROUND_COLOR:-"$foreground"} +else + TMUX_POWERLINE_DEFAULT_BACKGROUND_COLOR=${TMUX_POWERLINE_DEFAULT_BACKGROUND_COLOR:-'235'} + TMUX_POWERLINE_DEFAULT_FOREGROUND_COLOR=${TMUX_POWERLINE_DEFAULT_FOREGROUND_COLOR:-'255'} +fi +# shellcheck disable=SC2034 +TMUX_POWERLINE_SEG_AIR_COLOR=$(tp_air_color) + +TMUX_POWERLINE_DEFAULT_LEFTSIDE_SEPARATOR=${TMUX_POWERLINE_DEFAULT_LEFTSIDE_SEPARATOR:-$TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD} +TMUX_POWERLINE_DEFAULT_RIGHTSIDE_SEPARATOR=${TMUX_POWERLINE_DEFAULT_RIGHTSIDE_SEPARATOR:-$TMUX_POWERLINE_SEPARATOR_LEFT_BOLD} + +# See `man tmux` for additional formatting options for the status line. +# The `format regular` and `format inverse` functions are provided as conveniences + +# shellcheck disable=SC2128 +if [ -z "$TMUX_POWERLINE_WINDOW_STATUS_CURRENT" ]; then + TMUX_POWERLINE_WINDOW_STATUS_CURRENT=( + "#[$(tp_format inverse)]" + "$TMUX_POWERLINE_DEFAULT_LEFTSIDE_SEPARATOR" + " #I#F " + "$TMUX_POWERLINE_SEPARATOR_RIGHT_THIN" + " #W " + "#[$(tp_format regular)]" + "$TMUX_POWERLINE_DEFAULT_LEFTSIDE_SEPARATOR" + ) +fi + +# shellcheck disable=SC2128 +if [ -z "$TMUX_POWERLINE_WINDOW_STATUS_STYLE" ]; then + TMUX_POWERLINE_WINDOW_STATUS_STYLE=( + "$(tp_format regular)" + ) +fi + +# shellcheck disable=SC2128 +if [ -z "$TMUX_POWERLINE_WINDOW_STATUS_FORMAT" ]; then + TMUX_POWERLINE_WINDOW_STATUS_FORMAT=( + "#[$(tp_format regular)]" + " #I#{?window_flags,#F, } " + "$TMUX_POWERLINE_SEPARATOR_RIGHT_THIN" + " #W " + ) +fi + +# Format: segment_name [background_color|default_bg_color] [foreground_color|default_fg_color] [non_default_separator|default_separator] [separator_background_color|no_sep_bg_color] +# [separator_foreground_color|no_sep_fg_color] [spacing_disable|no_spacing_disable] [separator_disable|no_separator_disable] +# +# * background_color and foreground_color. Color formatting (see `man tmux` for complete list) or run the color_palette.sh in the tmux-powerline root directory: +# * Named colors, e.g. black, red, green, yellow, blue, magenta, cyan, white +# * Hexadecimal RGB string e.g. #ffffff +# * 'default_fg_color|default_bg_color' for the default theme bg and fg color +# * 'default' for the default tmux color. +# * 'terminal' for the terminal's default background/foreground color +# * The numbers 0-255 for the 256-color palette. Run `tmux-powerline/color-palette.sh` to see the colors. +# * non_default_separator - specify an alternative character for this segment's separator +# * 'default_separator' for the theme default separator +# * separator_background_color - specify a unique background color for the separator +# * 'no_sep_bg_color' for using the default coloring for the separator +# * separator_foreground_color - specify a unique foreground color for the separator +# * 'no_sep_fg_color' for using the default coloring for the separator +# * spacing_disable - remove space on left, right or both sides of the segment: +# * "no_spacing_disable" - don't disable spacing (default) +# * "left_disable" - disable space on the left +# * "right_disable" - disable space on the right +# * "both_disable" - disable spaces on both sides +# * - any other character/string produces no change to default behavior (eg "none", "X", etc.) +# +# * separator_disable - disables drawing a separator on this segment, very useful for segments +# with dynamic background colours (eg tmux_mem_cpu_load): +# * "no_separator_disable" - don't disable the separator (default) +# * "separator_disable" - disables the separator +# * - any other character/string produces no change to default behavior +# +# Example segment with separator disabled and right space character disabled: +# "hostname 33 0 {TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD} 0 0 right_disable separator_disable" +# +# Example segment with spacing characters disabled on both sides but not touching the default coloring: +# "hostname 33 0 {TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD} no_sep_bg_color no_sep_fg_color both_disable" +# +# Example segment with changing the foreground color of the default separator: +# "hostname 33 0 default_separator no_sep_bg_color 120" +# +## Note that although redundant the non_default_separator, separator_background_color and +# separator_foreground_color options must still be specified so that appropriate index +# of options to support the spacing_disable and separator_disable features can be used +# The default_* and no_* can be used to keep the default behaviour. + +# shellcheck disable=SC1143,SC2128 +if [ -z "$TMUX_POWERLINE_LEFT_STATUS_SEGMENTS" ]; then + # Use pywal colors if available, otherwise use defaults + # shellcheck disable=SC2154 + if [ -n "$color5" ] && [ -n "$background" ]; then + # shellcheck disable=SC2154 + TMUX_POWERLINE_LEFT_STATUS_SEGMENTS=( + # shellcheck disable=SC2154 + "tmux_session_info ${color5} ${background}" + # shellcheck disable=SC2154 + "hostname ${color3} ${background}" + #"mode_indicator 165 0" + #"ifstat 30 255" + #"ifstat_sys 30 255" + # shellcheck disable=SC2154 + # "lan_ip ${color6} ${background} ${TMUX_POWERLINE_SEPARATOR_RIGHT_THIN}" + #"vpn 24 255 ${TMUX_POWERLINE_SEPARATOR_RIGHT_THIN}" + # shellcheck disable=SC2154 + # "wan_ip ${color6} ${background} ${TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD} ${color2} ${background}" + # shellcheck disable=SC2154 + "vcs_branch ${color2} ${background}" + #"vcs_compare 60 255" + #"vcs_staged 64 255" + #"vcs_modified 9 255" + #"vcs_others 245 0" + ) + else + TMUX_POWERLINE_LEFT_STATUS_SEGMENTS=( + "tmux_session_info 148 234" + "hostname 33 0" + #"mode_indicator 165 0" + #"ifstat 30 255" + #"ifstat_sys 30 255" + # "lan_ip 24 255 ${TMUX_POWERLINE_SEPARATOR_RIGHT_THIN}" + #"vpn 24 255 ${TMUX_POWERLINE_SEPARATOR_RIGHT_THIN}" + # "wan_ip 24 255 ${TMUX_POWERLINE_SEPARATOR_RIGHT_BOLD} 29 255" + "vcs_branch 29 88" + #"vcs_compare 60 255" + #"vcs_staged 64 255" + #"vcs_modified 9 255" + #"vcs_others 245 0" + ) + fi +fi + +# shellcheck disable=SC1143,SC2128 +if [ -z "$TMUX_POWERLINE_RIGHT_STATUS_SEGMENTS" ]; then + # Use pywal colors if available, otherwise use defaults + # shellcheck disable=SC2154 + if [ -n "$color1" ] && [ -n "$background" ] && [ -n "$foreground" ]; then + # shellcheck disable=SC2154 + TMUX_POWERLINE_RIGHT_STATUS_SEGMENTS=( + #"earthquake 3 0" + # shellcheck disable=SC2154 + "pwd ${color4} ${background}" + #"macos_notification_count 29 255" + #"mailcount 9 255" + "now_playing 234 37" + #"cpu 240 136" + # shellcheck disable=SC2154 + # "load ${color8} ${background}" + #"tmux_mem_cpu_load 234 136" + # shellcheck disable=SC2154 + "battery ${color5} ${background}" + #"air ${TMUX_POWERLINE_SEG_AIR_COLOR} 255" + # shellcheck disable=SC2154 + "weather ${color14} ${background}" + #"rainbarf 0 ${TMUX_POWERLINE_DEFAULT_FOREGROUND_COLOR}" + # "$( + # if (($(tp_cpu_temp_at_least 60))); then + # echo "cpu_temp #ff2020 235" + # else + # echo "cpu_temp #303080 136" + # fi + # )" \ + #"xkb_layout 125 117" + #"tmux_continuum_save" + #"tmux_continuum_status 14 7" + # shellcheck disable=SC2154 + "date_day ${color1} ${background}" + # shellcheck disable=SC2154 + "date ${color1} ${background} ${TMUX_POWERLINE_SEPARATOR_LEFT_THIN}" + # shellcheck disable=SC2154 + "time ${color1} ${background} ${TMUX_POWERLINE_SEPARATOR_LEFT_THIN}" + #"utc_time 235 136 ${TMUX_POWERLINE_SEPARATOR_LEFT_THIN}" + ) + else + TMUX_POWERLINE_RIGHT_STATUS_SEGMENTS=( + #"earthquake 3 0" + "pwd 89 211" + #"macos_notification_count 29 255" + #"mailcount 9 255" + "now_playing 234 37" + #"cpu 240 136" + # "load 237 167" + #"tmux_mem_cpu_load 234 136" + "battery 137 127" + #"air ${TMUX_POWERLINE_SEG_AIR_COLOR} 255" + "weather 37 255" + #"rainbarf 0 ${TMUX_POWERLINE_DEFAULT_FOREGROUND_COLOR}" + # "$( + # if (($(tp_cpu_temp_at_least 60))); then + # echo "cpu_temp #ff2020 235" + # else + # echo "cpu_temp #303080 136" + # fi + # )" \ + #"xkb_layout 125 117" + #"tmux_continuum_save" + #"tmux_continuum_status 14 7" + "date_day 235 136" + "date 235 136 ${TMUX_POWERLINE_SEPARATOR_LEFT_THIN}" + "time 235 136 ${TMUX_POWERLINE_SEPARATOR_LEFT_THIN}" + #"utc_time 235 136 ${TMUX_POWERLINE_SEPARATOR_LEFT_THIN}" + ) + fi +fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ca9a38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +firefox/ +.DS_Store +.lazy.lua +*.venv*
\ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e92d133 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,33 @@ +[submodule ".oh-my-zsh/custom/plugins/zsh-autosuggestions"] + path = .oh-my-zsh/custom/plugins/zsh-autosuggestions + url = https://github.com/zsh-users/zsh-autosuggestions.git +[submodule ".oh-my-zsh/custom/plugins/zsh-syntax-highlighting"] + path = .oh-my-zsh/custom/plugins/zsh-syntax-highlighting + url = https://github.com/zsh-users/zsh-syntax-highlighting.git +[submodule ".oh-my-zsh/custom/plugins/zsh-autocomplete"] + path = .oh-my-zsh/custom/plugins/zsh-autocomplete + url = https://github.com/marlonrichert/zsh-autocomplete.git +[submodule ".tmux/plugins/tmux-autoreload"] + path = .tmux/plugins/tmux-autoreload + url = https://github.com/b0o/tmux-autoreload.git +[submodule ".tmux/plugins/tmux-continuum"] + path = .tmux/plugins/tmux-continuum + url = https://github.com/tmux-plugins/tmux-continuum.git +[submodule ".tmux/plugins/tmux-logging"] + path = .tmux/plugins/tmux-logging + url = https://github.com/tmux-plugins/tmux-logging.git +[submodule ".tmux/plugins/tmux-mighty-scroll"] + path = .tmux/plugins/tmux-mighty-scroll + url = https://github.com/noscript/tmux-mighty-scroll.git +[submodule ".tmux/plugins/tmux-powerline"] + path = .tmux/plugins/tmux-powerline + url = https://github.com/erikw/tmux-powerline.git +[submodule ".tmux/plugins/tmux-resurrect"] + path = .tmux/plugins/tmux-resurrect + url = https://github.com/tmux-plugins/tmux-resurrect.git +[submodule ".tmux/plugins/tmux-sensible"] + path = .tmux/plugins/tmux-sensible + url = https://github.com/tmux-plugins/tmux-sensible.git +[submodule ".tmux/plugins/tpm"] + path = .tmux/plugins/tpm + url = https://github.com/tmux-plugins/tpm.git diff --git a/.irssi/config b/.irssi/config new file mode 100644 index 0000000..ac5d6d2 --- /dev/null +++ b/.irssi/config @@ -0,0 +1,331 @@ +servers = ( + { address = "irc.dal.net"; chatnet = "DALnet"; port = "6667"; }, + { + address = "ssl.efnet.org"; + chatnet = "EFNet"; + port = "9999"; + use_tls = "yes"; + tls_verify = "no"; + }, + { + address = "irc.esper.net"; + chatnet = "EsperNet"; + port = "6697"; + use_tls = "yes"; + tls_verify = "yes"; + }, + { + address = "irc.libera.chat"; + chatnet = "liberachat"; + port = "6697"; + use_tls = "yes"; + tls_verify = "yes"; + autoconnect = "yes"; + }, + { + address = "irc.gamesurge.net"; + chatnet = "GameSurge"; + port = "6667"; + }, + { + address = "ssl.ircnet.ovh"; + chatnet = "IRCnet"; + port = "6697"; + use_tls = "yes"; + tls_verify = "yes"; + }, + { address = "open.ircnet.net"; chatnet = "IRCnet"; port = "6667"; }, + { + address = "irc.ircsource.net"; + chatnet = "IRCSource"; + port = "6667"; + }, + { address = "irc.netfuze.net"; chatnet = "NetFuze"; port = "6667"; }, + { + address = "irc.oftc.net"; + chatnet = "OFTC"; + port = "6697"; + use_tls = "yes"; + tls_verify = "yes"; + }, + { + address = "irc.quakenet.org"; + chatnet = "QuakeNet"; + port = "6667"; + }, + { + address = "irc.rizon.net"; + chatnet = "Rizon"; + port = "6697"; + use_tls = "yes"; + tls_verify = "yes"; + }, + { address = "silc.silcnet.org"; chatnet = "SILC"; port = "706"; }, + { + address = "irc.undernet.org"; + chatnet = "Undernet"; + port = "6667"; + } +); + +chatnets = { + DALnet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "20"; + max_whois = "30"; + }; + EFNet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "4"; + max_whois = "1"; + }; + EsperNet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "4"; + max_whois = "1"; + }; + liberachat = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "4"; + max_whois = "1"; + sasl_mechanism = "PLAIN"; + sasl_username = ""; + sasl_password = ""; + }; + GameSurge = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "1"; + max_whois = "1"; + }; + IRCnet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "1"; + max_whois = "1"; + }; + IRCSource = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "4"; + max_whois = "1"; + }; + NetFuze = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "1"; + max_whois = "1"; + }; + OFTC = { type = "IRC"; max_kicks = "1"; max_msgs = "1"; max_whois = "1"; }; + QuakeNet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "1"; + max_whois = "1"; + }; + Rizon = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "1"; + max_whois = "1"; + }; + SILC = { type = "SILC"; }; + Undernet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "1"; + max_whois = "1"; + }; +}; + +channels = ( + { name = "#lobby"; chatnet = "EsperNet"; autojoin = "No"; }, + { name = "#libera"; chatnet = "liberachat"; autojoin = "No"; }, + { name = "#irssi"; chatnet = "liberachat"; autojoin = "No"; }, + { name = "#gamesurge"; chatnet = "GameSurge"; autojoin = "No"; }, + { name = "#irssi"; chatnet = "IRCNet"; autojoin = "No"; }, + { name = "#ircsource"; chatnet = "IRCSource"; autojoin = "No"; }, + { name = "#netfuze"; chatnet = "NetFuze"; autojoin = "No"; }, + { name = "#oftc"; chatnet = "OFTC"; autojoin = "No"; }, + { name = "silc"; chatnet = "SILC"; autojoin = "No"; } +); + +aliases = { + ATAG = "WINDOW SERVER"; + ADDALLCHANS = "SCRIPT EXEC foreach my \\$channel (Irssi::channels()) { Irssi::command(\"CHANNEL ADD -auto \\$channel->{visible_name} \\$channel->{server}->{tag} \\$channel->{key}\")\\;}"; + B = "BAN"; + BACK = "AWAY"; + BANS = "BAN"; + BYE = "QUIT"; + C = "CLEAR"; + CALC = "EXEC - if command -v bc >/dev/null 2>&1\\; then printf '%s=' '$*'\\; echo '$*' | bc -l\\; else echo bc was not found\\; fi"; + CHAT = "DCC CHAT"; + CS = "QUOTE CS"; + DATE = "TIME"; + DEHIGHLIGHT = "DEHILIGHT"; + DESCRIBE = "ACTION"; + DHL = "DEHILIGHT"; + EXEMPTLIST = "MODE $C +e"; + EXIT = "QUIT"; + GOTO = "SCROLLBACK GOTO"; + HIGHLIGHT = "HILIGHT"; + HL = "HILIGHT"; + HOST = "USERHOST"; + INVITELIST = "MODE $C +I"; + J = "JOIN"; + K = "KICK"; + KB = "KICKBAN"; + KN = "KNOCKOUT"; + LAST = "LASTLOG"; + LEAVE = "PART"; + M = "MSG"; + MS = "QUOTE MS"; + MUB = "UNBAN *"; + N = "NAMES"; + NMSG = "^MSG"; + NS = "QUOTE NS"; + OS = "QUOTE OS"; + P = "PART"; + Q = "QUERY"; + RESET = "SET -default"; + RUN = "SCRIPT LOAD"; + SAY = "MSG *"; + SB = "SCROLLBACK"; + SBAR = "STATUSBAR"; + SHELP = "QUOTE HELP"; + SIGNOFF = "QUIT"; + SV = "MSG * Irssi $J ($V) - https://irssi.org"; + T = "TOPIC"; + UB = "UNBAN"; + UMODE = "MODE $N"; + UNSET = "SET -clear"; + W = "WHO"; + WC = "WINDOW CLOSE"; + WG = "WINDOW GOTO"; + WJOIN = "JOIN -window"; + WI = "WHOIS"; + WII = "WHOIS $0 $0"; + WL = "WINDOW LIST"; + WN = "WINDOW NEW HIDDEN"; + WQUERY = "QUERY -window"; + WW = "WHOWAS"; +}; + +statusbar = { + + items = { + + barstart = "{sbstart}"; + barend = "{sbend}"; + + topicbarstart = "{topicsbstart}"; + topicbarend = "{topicsbend}"; + + time = "{sb $Z}"; + user = "{sb {sbnickmode $cumode}$N{sbmode $usermode}{sbaway $A}}"; + + window = "{sb $winref:$tag/$itemname{sbmode $M}}"; + window_empty = "{sb $winref{sbservertag $tag}}"; + + prompt = "{prompt $[.15]itemname}"; + prompt_empty = "{prompt $winname}"; + + topic = " $topic"; + topic_empty = " Irssi v$J - https://irssi.org"; + + lag = "{sb Lag: $0-}"; + act = "{sb Act: $0-}"; + more = "-- more --"; + }; + + default = { + + window = { + + disabled = "no"; + type = "window"; + placement = "bottom"; + position = "1"; + visible = "active"; + + items = { + barstart = { priority = "100"; }; + time = { }; + user = { }; + window = { }; + window_empty = { }; + lag = { priority = "-1"; }; + act = { priority = "10"; }; + more = { priority = "-1"; alignment = "right"; }; + barend = { priority = "100"; alignment = "right"; }; + }; + }; + + window_inact = { + + type = "window"; + placement = "bottom"; + position = "1"; + visible = "inactive"; + + items = { + barstart = { priority = "100"; }; + window = { }; + window_empty = { }; + more = { priority = "-1"; alignment = "right"; }; + barend = { priority = "100"; alignment = "right"; }; + }; + }; + + prompt = { + + type = "root"; + placement = "bottom"; + position = "100"; + visible = "always"; + + items = { + prompt = { priority = "-1"; }; + prompt_empty = { priority = "-1"; }; + input = { priority = "10"; }; + }; + }; + + topic = { + + type = "root"; + placement = "top"; + position = "1"; + visible = "always"; + + items = { + topicbarstart = { priority = "100"; }; + topic = { }; + topic_empty = { }; + topicbarend = { priority = "100"; alignment = "right"; }; + }; + }; + }; +}; +settings = { + core = { + real_name = ""; + user_name = ""; + nick = ""; + }; + "fe-common/core" = { theme = "pipeline"; }; + "perl/core/scripts" = { + awl_shared_sbar = "OFF"; + neat_maxlength = "16"; + neat_dynamic = "no"; + awl_viewer_launch_env = "NOTITLE=1"; + }; +}; +keyboard = ( + { key = "meta-[M"; id = "command"; data = "mouse_xterm "; } +); +ignores = ( { level = "JOINS PARTS QUITS"; } ); diff --git a/.irssi/default.theme b/.irssi/default.theme new file mode 100644 index 0000000..79b1af5 --- /dev/null +++ b/.irssi/default.theme @@ -0,0 +1,295 @@ +# When testing changes, the easiest way to reload the theme is with /RELOAD. +# This reloads the configuration file too, so if you did any changes remember +# to /SAVE it first. Remember also that /SAVE overwrites the theme file with +# old data so keep backups :) + +# TEMPLATES: + +# The real text formats that irssi uses are the ones you can find with +# /FORMAT command. Back in the old days all the colors and texts were mixed +# up in those formats, and it was really hard to change the colors since you +# might have had to change them in tens of different places. So, then came +# this templating system. + +# Now the /FORMATs don't have any colors in them, and they also have very +# little other styling. Most of the stuff you need to change is in this +# theme file. If you can't change something here, you can always go back +# to change the /FORMATs directly, they're also saved in these .theme files. + +# So .. the templates. They're those {blahblah} parts you see all over the +# /FORMATs and here. Their usage is simply {name parameter1 parameter2}. +# When irssi sees this kind of text, it goes to find "name" from abstracts +# block below and sets "parameter1" into $0 and "parameter2" into $1 (you +# can have more parameters of course). Templates can have subtemplates. +# Here's a small example: +# /FORMAT format hello {colorify {underline world}} +# abstracts = { colorify = "%G$0-%n"; underline = "%U$0-%U"; } +# When irssi expands the templates in "format", the final string would be: +# hello %G%Uworld%U%n +# ie. underlined bright green "world" text. +# and why "$0-", why not "$0"? $0 would only mean the first parameter, +# $0- means all the parameters. With {underline hello world} you'd really +# want to underline both of the words, not just the hello (and world would +# actually be removed entirely). + +# COLORS: + +# You can find definitions for the color format codes in docs/formats.txt. + +# There's one difference here though. %n format. Normally it means the +# default color of the terminal (white mostly), but here it means the +# "reset color back to the one it was in higher template". For example +# if there was /FORMAT test %g{foo}bar, and foo = "%Y$0%n", irssi would +# print yellow "foo" (as set with %Y) but "bar" would be green, which was +# set at the beginning before the {foo} template. If there wasn't the %g +# at start, the normal behaviour of %n would occur. If you _really_ want +# to use the terminal's default color, use %N. + +############################################################################# + +# default foreground color (%N) - -1 is the "default terminal color" +default_color = "-1"; + +# print timestamp/servertag at the end of line, not at beginning +info_eol = "false"; + +# these characters are automatically replaced with specified color +# (dark grey by default) +replaces = { "[]=" = "%K$*%n"; }; + +abstracts = { + ## + ## generic + ## + + # text to insert at the beginning of each non-message line + line_start = "%B-%n!%B-%n "; + + # timestamp styling, nothing by default + timestamp = "$*"; + + # any kind of text that needs hilighting, default is to bold + hilight = "%_$*%_"; + + # any kind of error message, default is bright red + error = "%R$*%n"; + + # channel name is printed + channel = "%_$*%_"; + + # nick is printed + nick = "%_$*%_"; + + # nick host is printed + nickhost = "[$*]"; + + # server name is printed + server = "%_$*%_"; + + # some kind of comment is printed + comment = "[$*]"; + + # reason for something is printed (part, quit, kick, ..) + reason = "{comment $*}"; + + # mode change is printed ([+o nick]) + mode = "{comment $*}"; + + ## + ## channel specific messages + ## + + # highlighted nick/host is printed (joins) + channick_hilight = "%C$*%n"; + chanhost_hilight = "{nickhost %c$*%n}"; + + # nick/host is printed (parts, quits, etc.) + channick = "%c$*%n"; + chanhost = "{nickhost $*}"; + + # highlighted channel name is printed + channelhilight = "%c$*%n"; + + # ban/ban exception/invite list mask is printed + ban = "%c$*%n"; + + ## + ## messages + ## + + # the basic styling of how to print message, $0 = nick mode, $1 = nick + msgnick = "%K<%n$0$1-%K>%n %|"; + + # message from you is printed. "ownnick" specifies the styling of the + # nick ($0 part in msgnick) and "ownmsgnick" specifies the styling of the + # whole line. + + # Example1: You want the message text to be green: + # ownmsgnick = "{msgnick $0 $1-}%g"; + # Example2.1: You want < and > chars to be yellow: + # ownmsgnick = "%Y{msgnick $0 $1-%Y}%n"; + # (you'll also have to remove <> from replaces list above) + # Example2.2: But you still want to keep <> grey for other messages: + # pubmsgnick = "%K{msgnick $0 $1-%K}%n"; + # pubmsgmenick = "%K{msgnick $0 $1-%K}%n"; + # pubmsghinick = "%K{msgnick $1 $0$2-%n%K}%n"; + # ownprivmsgnick = "%K{msgnick $*%K}%n"; + # privmsgnick = "%K{msgnick %R$*%K}%n"; + + # $0 = nick mode, $1 = nick + ownmsgnick = "{msgnick $0 $1-}"; + ownnick = "%_$*%n"; + + # public message in channel, $0 = nick mode, $1 = nick + pubmsgnick = "{msgnick $0 $1-}"; + pubnick = "%N$*%n"; + + # public message in channel meant for me, $0 = nick mode, $1 = nick + pubmsgmenick = "{msgnick $0 $1-}"; + menick = "%Y$*%n"; + + # public highlighted message in channel + # $0 = highlight color, $1 = nick mode, $2 = nick + pubmsghinick = "{msgnick $1 $0$2-%n}"; + + # channel name is printed with message + msgchannel = "%K:%c$*%n"; + + # private message, $0 = nick, $1 = host + privmsg = "[%R$0%K(%r$1-%K)%n] "; + + # private message from you, $0 = "msg", $1 = target nick + ownprivmsg = "[%r$0%K(%R$1-%K)%n] "; + + # own private message in query + ownprivmsgnick = "{msgnick $*}"; + ownprivnick = "%_$*%n"; + + # private message in query + privmsgnick = "{msgnick %R$*%n}"; + + ## + ## Actions (/ME stuff) + ## + + # used internally by this theme + action_core = "%_ * $*%n"; + + # generic one that's used by most actions + action = "{action_core $*} "; + + # own action, both private/public + ownaction = "{action $*}"; + + # own action with target, both private/public + ownaction_target = "{action_core $0}%K:%c$1%n "; + + # private action sent by others + pvtaction = "%_ (*) $*%n "; + pvtaction_query = "{action $*}"; + + # public action sent by others + pubaction = "{action $*}"; + + + ## + ## other IRC events + ## + + # whois + whois = "%# $[8]0 : $1-"; + + # notices + ownnotice = "[%r$0%K(%R$1-%K)]%n "; + notice = "%K-%M$*%K-%n "; + pubnotice_channel = "%K:%m$*"; + pvtnotice_host = "%K(%m$*%K)"; + servernotice = "%g!$*%n "; + + # CTCPs + ownctcp = "[%r$0%K(%R$1-%K)] "; + ctcp = "%g$*%n"; + + # wallops + wallop = "%_$*%n: "; + wallop_nick = "%n$*"; + wallop_action = "%_ * $*%n "; + + # netsplits + netsplit = "%R$*%n"; + netjoin = "%C$*%n"; + + # /names list + names_prefix = ""; + names_nick = "[%_$0%_$1-] "; + names_nick_op = "{names_nick $*}"; + names_nick_halfop = "{names_nick $*}"; + names_nick_voice = "{names_nick $*}"; + names_users = "[%g$*%n]"; + names_channel = "%G$*%n"; + + # DCC + dcc = "%g$*%n"; + dccfile = "%_$*%_"; + + # DCC chat, own msg/action + dccownmsg = "[%r$0%K($1-%K)%n] "; + dccownnick = "%R$*%n"; + dccownquerynick = "%_$*%n"; + dccownaction = "{action $*}"; + dccownaction_target = "{action_core $0}%K:%c$1%n "; + + # DCC chat, others + dccmsg = "[%G$1-%K(%g$0%K)%n] "; + dccquerynick = "%G$*%n"; + dccaction = "%_ (*dcc*) $*%n %|"; + + ## + ## statusbar + ## + + # default background for all statusbars. You can also give + # the default foreground color for statusbar items. + sb_background = "%4%w"; + window_border = "%4%w"; + + # default backround for "default" statusbar group + #sb_default_bg = "%4"; + # background for prompt / input line + sb_prompt_bg = "%n"; + # background for info statusbar + sb_info_bg = "%8"; + # background for topicbar (same default) + #sb_topic_bg = "%4"; + + # text at the beginning of statusbars. "sb" already puts a space there, + # so we don't use anything by default. + sbstart = ""; + # text at the end of statusbars. Use space so that it's never + # used for anything. + sbend = " "; + + topicsbstart = "{sbstart $*}"; + topicsbend = "{sbend $*}"; + + prompt = "[$*] "; + + sb = " %c[%n$*%c]%n"; + sbmode = "(%c+%n$*)"; + sbaway = " (%GzZzZ%n)"; + sbservertag = ":$0 (change with ^X)"; + sbnickmode = "$0"; + + # activity in statusbar + + # ',' separator + sb_act_sep = "%c$*"; + # normal text + sb_act_text = "%c$*"; + # public message + sb_act_msg = "%W$*"; + # hilight + sb_act_hilight = "%M$*"; + # hilight with specified color, $0 = color, $1 = text + sb_act_hilight_color = "$0$1-%n"; +}; diff --git a/.irssi/neongold.theme b/.irssi/neongold.theme new file mode 100644 index 0000000..b624f03 --- /dev/null +++ b/.irssi/neongold.theme @@ -0,0 +1,206 @@ +# +# ███████ █████ ██████ ███████ +# ░░██░░░██ ██░░░██ ██░░░░██░░██░░░██ +# ░██ ░██░███████░██ ░██ ░██ ░██ +# ░██ ░██░██░░░░ ░██ ░██ ░██ ░██ +# ███ ░██░░██████░░██████ ███ ░██ +# ░░░ ░░ ░░░░░░ ░░░░░░ ░░░ ░░ +# +# ██ ██ +# ░██ ░██ +# █████ ██████ ░██ ░██ +# ██░░░██ ██░░░░██ ░██ ██████ +# ░██ ░██░██ ░██ ░██ ██░░░██ +# ░░██████░██ ░██ ░██░██ ░██ +# ░░░░░██░░██████ ███░░██████ +# █████ ░░░░░░ ░░░ ░░░░░░ +# ░░░░░ +# +# ▓▓▓▓▓▓▓▓▓▓ +# ░▓ author ▓ xero <x@xero.nu> +# ░▓ code ▓ http://code.xero.nu/dotfiles +# ░▓ mirror ▓ http://git.io/.files +# ░▓▓▓▓▓▓▓▓▓▓ +# ░░░░░░░░░░ +# +default_color = "-1"; + +info_eol = "false"; + +replaces = { "[]" = "%w$*%n"; }; + +abstracts = { + + indent_default = " + %Y│%n "; + line_start = ""; + timestamp = ""; + hilight = "%_$*%_"; + error = "%r$*%n"; + channel = "%w$*%n"; + nick = "%_$*%_"; + nickhost = "%g$*"; + server = "%_$*%_"; + comment = "%n(%w$*%n)"; + reason = "{comment $*}"; + mode = "{comment $*}"; + + channick_hilight = "%g$*%N"; + chanhost_hilight = "{nickhost $*}"; + + channick = "$*"; + chanhost = "{nickhost $*}"; + + channelhilight = "%g$*%n"; + + ban = "$*"; + + msgnick = "%Y$0%w$1 %Y│ %N"; + ownmsgnick = "%Y$0%w$1 %Y│ "; + ownnick = "%W$*%n"; + pubnick = "%N$*%n"; + menick = "%y$*%y"; + + # generic one that's used by most actions + action = "%b$* %Y│%b"; + + # own action, both private/public + ownaction = "%b$* %Y│%b"; + + # own action with target, both private/public + ownaction_target = "{action $*}"; + + # private action sent by others + pvtaction = "{action $*}"; + pvtaction_query = "{action $*}"; + + # public action sent by others + pubaction = "{action $*}"; + + whois = "%w │ %n$1-"; + + ownnotice = "%NNote n = %Mnew%n $0 ($1-) "; + notice = "%M$*%n "; + pubnotice_channel = " %N($*)"; + pvtnotice_host = " %N($*)"; + servernotice = " %N($*)"; + + ownctcp = "%N$0 (%w$1-%N) "; + ctcp = "%N$*%n"; + + wallop = "%w$*%n: "; + wallop_nick = "%n$*"; + wallop_action = "%w * $*%n "; + + #netsplit = "%w$*%n"; + #netjoin = "%w$*%n"; + + names_users = "%Y┌─┄┄─┄┄──┘ %nusers in %b$1"; + names_nick = "$2$0%n$1 "; + names_nick_op = "{names_nick $* %w}"; + names_nick_halfop = "{names_nick $* %w}"; + names_nick_voice = "{names_nick $* %w}"; + names_prefix = "%Y│ %n$1"; + names_channel = "%W$*%n"; + + dcc = "%g$*%n"; + dccfile = "%_$*%_"; + + dccownmsg = "%g /* $0 ($1-) */"; + dccownnick = "$*%n"; + dccownquerynick = "$*%n"; + dccownaction = "{action $*}"; + dccownaction_target = "{action $*}"; + + dccmsg = "%g/* $1- ($0) */"; + dccquerynick = "%g$*%n"; + dccaction = "{action $*}"; + + sb_background = "%N%N"; + + sb_prompt_bg = "%n"; + + sbstart = " %Y┌─┄┄─────┘ %w"; + sbend = ""; + + topicsbstart = "%w$C %Y┄─┄$*"; + topicsbend = "$*"; + + prompt = " %Y└──┄┄%n "; + + sb = "%N$*%N "; + #sb = ""; + sbmode = "%b(%w+%N$*%b)%n"; + sbaway = "%b(%Naway%b)%N"; + sbservertag = "%b:%N$0%b(%N^X%b)"; + #sbservertag = ""; + sbnickmode = "%w$0%N$1"; + + #sb_usercount = "{sb %_$0%_ nicks ($1-)}"; + #sb_uc_ircops = "%_*%_$*"; + #sb_uc_ops = "%_@%r$*%n"; + #sb_uc_halfops = "%_%%%g$*%n"; + #sb_uc_voices = "%_+%y$*%n"; + #sb_uc_normal = "%w$*%n"; + #sb_uc_space = " "; + + #sb_act_sep = "%b$*"; + #sb_act_text = "%N$*"; + #sb_act_msg = "%b$*"; + #sb_act_hilight = "%R%9$*%n"; + #sb_act_hilight_color = "%R%9$1-%n"; +}; + +formats = { + "fe-common/core" = { + #line_start = "{line_start}"; + line_start_irssi = "{line_start}"; + join = "%n join %Y┄┄─┤ %n{channick $0} %w(%n{nickhost %w$1}%w)%n joined %w$2"; + part = "%n part %Y┄┄─┤ %n{channick $0} %w(%n{nickhost %w$1}%w)%n left %w$2 {reason %b$3}"; + quit = "%n quit %Y┄┄─┤ %nsignoff%w: %n{channick $0}%w {reason %b$2}"; + kick = "%r kick %Y┄┄─┤ %n{channick $0} was kicked by $2 %w{reason %b$3}"; + nick_changed = " %Y┄┼┄%w %n{channick $0} %Y>> %W{channick $1}"; + your_nick_changed = " %Y┄┼┄%w %n{channick $0} %Y>> %W{channick $1}"; + new_topic = "%Y┌─┄┄─────┘%n\012%Y│ %wtopic %b'$2' %Nset by%b $0\012%Y└─┄┄─┄┄──┐ "; + endofnames = "%Y└─┄┄─┄┄──┐ %btotal: {hilight $2} ops, {hilight $3} halfops, {hilight $4} voices, {hilight $5} normals%n"; + #nick padding + pubmsg = "{pubmsgnick $2 {pubnick \00312$[-7]0}}$1"; + own_msg = "{ownmsgnick $2 {ownnick $[-7]0}}$1"; + own_msg_channel = "{ownmsgnick $3 {ownnick $[-7]0}{msgchannel $1}}$2"; + own_msg_private_query = "{ownprivmsgnick {ownprivnick $[-7]2}}$1"; + pubmsg_me = "{pubmsghinick $[-7]0 {menick $2}}%y$1"; + pubmsg_me_channel = "{pubmsghinick $3 {menick $[-7]0}{msgchannel $1}}$2"; + pubmsg_hilight_channel = "{pubmsghinick $0 $[-7]1$4{msgchannel $2}}$3"; + pubmsg_hilight = "{pubmsghinick $3 {menick $[-7]1}}$2"; + pubmsg_channel = "{pubmsgnick {pubnick %G$[-7]0}$2}$1"; + msg_private_query = "{privmsgnick $[-7]0}$2"; + }; + "fe-common/irc" = { + chanmode_change = "%n mode %Y┄┄─┤ %w(%B{channick $1}%w) %nby %B$2"; + server_chanmode_change = "%n mode %Y┄┄─┤ %w{channick $1} %n(%w$2%n)"; + whois = "%Y┌─┄┄ %n\012%Y│ %wuser %b$0 %w(%n$1%b@%n$2%w) %n\012%Y│ %wname %n$3%n"; + whois_idle = "%Y│ %widle%b %|$1d $2h $3m $4s"; + whois_idle_signon = "%Y│ %widle%b %|$1d $2h $3m $4s {comment signon: $5}"; + whois_server = "%Y│ %wserv%b %|$1 {comment $2}"; + whois_oper = "%Y│ %woper%b {hilight $1}"; + whois_registered = "%Y│ %wrgis%n yes"; + whois_help = "%Y│ %whelp%b available for help"; + whois_modes = "%Y│ %wmode%b $1"; + whois_realhost = "%Y│ %wreal%b $1-"; + whois_usermode = "%Y│ %wumod%b $1"; + whois_channels = "%Y│ %wchan%b %|$1"; + whois_away = "%Y│ %waway%b %|$1"; + whois_special = "%Y│ %winfo%b {comment %|$1}"; + whois_extra = "%Y│ %wextr%b %|$1"; + end_of_whois = "%Y└─┄┄ "; + whois_not_found = "%Y──┄┄ %wthere is no such nick %b$0"; + topic = "%ntopic %Y┄┄─┤ %B$0 %b$1"; + topic_info = " %Y┄┄─┤ %wset by %b$0 %B(%w$1%B)"; + channel_synced = "%n sync %Y┄┄─┤ %nin {hilight $1} secs"; + channel_created = "%n %Y┄┄─┤ %ncreated $1"; + action_core = "%b$[-8]0 %Y│ %b$1"; + own_action = "{ownaction $[-8]0} $1"; + action_private = "{pvtaction $[-8]0}$1"; + action_private_query = "{pvtaction_query $[-8} $2"; + action_public = "{pubaction $[-8]0}$1"; + }; +}; diff --git a/.irssi/pipeline.theme b/.irssi/pipeline.theme new file mode 100644 index 0000000..15b5bff --- /dev/null +++ b/.irssi/pipeline.theme @@ -0,0 +1,270 @@ +#!/bin/bash +# +# pipeline +# +# An Irssi theme inspired by madcow and skeita +# +# Copyright (c) 2016 Beau Hastings. All rights reserved. +# License: GNU General Public License v2 +# +# Author: Beau Hastings <beausy@gmail.com> +# URL: https://github.com/hastinbe/irssi-theme-pipeline + +replaces = { "/[]=" = "%K$*%n"; "*@+." = "%B$*%n"; }; + +#replaces = { "!@+" = "%r$*%n"; }; +info_eol = "false"; + +abstracts = { + ## + ## generic + ## + + # text to insert at the beginning of each non-message line + #line_start = "%b.%c.%C.%n "; + line_start = ""; + + # timestamp styling, nothing by default + timestamp = "%B$*%n"; + #timestamp = "%y$*%n"; + + # any kind of text that needs hilighting, default is to bold + hilight = "%_$*%_"; + + # any kind of error message, default is bright red + error = "%R$*%n"; + + # channel name is printed + #channel = "$*"; + channel = "%_$*%_"; + + # nick is printed + nick = "$*"; + + # nick host is printed + nickhost = "$*"; + + # server name is printed + server = "%_$*%_"; + + # some kind of comment is printed + #comment = "$*"; + comment = "%b[%n$*%b]%n"; + + # reason for something is printed (part, quit, kick, ..) + reason = "{comment %_$*%_}"; + + # mode change is printed ([+o nick]) + #mode = "{comment %n[%W$*]%n}"; + mode = "%b$*%n"; + + ## + ## channel specific messages + ## + + # highlighted nick/host is printed (joins) + channick_hilight = "$*"; + chanhost_hilight = "{nickhost $*}"; + + # nick/host is printed (parts, quits, etc.) + channick = "%W$*%n"; + chanhost = "{nickhost $*}"; + + # highlighted channel name is printed + channelhilight = "%R$*%n"; + + # ban/ban exception/invite list mask is printed + ban = "%r$*%n"; + + ## + ## messages + ## + + # the basic styling of how to print message, $0 = nick mode, $1 = nick + #msgnick = "<%C$0%n$1-%n> %|"; + msgnick = "%b%n$0$1%K |%n %|"; + + # message from you is printed. "msgownnick" specifies the styling of the + # nick ($0 part in msgnick) and "ownmsgnick" specifies the styling of the + # whole line. + + # Example1: You want the message text to be green: + # ownmsgnick = "{msgnick $0 $1-}%g"; + # Example2.1: You want < and > chars to be yellow: + # ownmsgnick = "%Y{msgnick $0 $1-%Y}%n"; + # (you'll also have to remove <> from replaces list above) + # Example2.2: But you still want to keep <> grey for other messages: + # pubmsgnick = "%K{msgnick $0 $1-%K}%n"; + # pubmsgmenick = "%K{msgnick $0 $1-%K}%n"; + # pubmsghinick = "%K{msgnick $1 $0$2-%n%K}%n"; + # ownprivmsgnick = "%K{msgnick $*%K}%n"; + # privmsgnick = "%K{msgnick %R$*%K}%n"; + + # $0 = nick mode, $1 = nick + ownmsgnick = "{msgnick $0 $1-}%W"; + ownnick = "%y$*%n"; + + # public message in channel, $0 = nick mode, $1 = nick + pubmsgnick = "{msgnick %b$0%n %w$1%n}"; + #pubmsgnick = "{msgnick $0$1-}"; + pubnick = "%w$*%n"; + + # public message in channel meant for me, $0 = nick mode, $1 = nick + #pubmsgmenick = "%Y{msgnick %B$0%n %w$1%n}%w"; + pubmsgmenick = "{msgnick $0$1-}"; + menick = "%g$*%n"; + + # public highlighted message in channel + # $0 = highlight color, $1 = nick mode, $2 = nick + #pubmsghinick = "%Y{msgnick %B$1 %w$2}%w"; + pubmsghinick = "{msgnick $1 $0$2-%n}"; + + # channel name is printed with message + msgchannel = "%b:$*%n"; + + # private message, $0 = nick, $1 = host + #privmsg = "%b.%c.%C.%n(%c$0%n[%c$1]) "; + privmsg = "[%w$0!%b$1-%n] "; + + # private message from you, $0 = "msg", $1 = target nick + #ownprivmsg = "%b.%c.%C.%n[%cmsg%n(%c$1%n)] "; + ownprivmsg = "{msgnick $*}"; + + # own private message in query + ownprivmsgnick = "{msgnick %W$*%w}"; + ownprivnick = "%W$0%n%w"; + + # private message in query + privmsgnick = "{msgnick %B$*%w}"; + + ## + ## Actions (/ME stuff) + ## + + # used internally by this theme + action_core = "%W*%w $*%n"; + + # generic one that's used by most actions + action = "%w{action_core %w$*} "; + + # own action, both private/public + ownaction = "{action $*}"; + + # own action with target, both private/public + ownaction_target = "{action_core $0}%K:%b$1%n "; + + # private action sent by others + pvtaction = "%w $*%n "; + pvtaction_query = "{action $*}"; + + # public action sent by others + pubaction = "{action $*}"; + + + ## + ## other IRC events + ## + + # notices + ownnotice = "%b>%c>%C> %c$0%B!%c$1%n: "; + notice = "%b$*%n "; + pubnotice_channel = "%K:%m$*"; + pubnotice_host = "%K(%m$*%K)"; + servernotice = "%g!$*%n "; + + # CTCPs + ownctcp = "%b>%c>%C> %c$0%B!%c$1%n: "; + ctcp = "%m$*%n"; + + # wallops + wallop = "%W$*%n: "; + wallop_nick = "%n$*"; + wallop_action = "%W * $*%n "; + + # netsplits + netsplit = "%B$*%n"; + netjoin = "%B$*%n"; + + # /names list + names_nick = "[%_$0%_%w$1-%n] "; + names_users = "%b$*%n:"; + names_channel = "%B$*%n"; + + # DCC + dcc = "%b$*%n"; + dccfile = "%_$*%_"; + + # DCC chat, own msg/action + dccownmsg = "[%b$0%K($1-%K)%n] "; + dccownnick = "%B$*%n"; + dccownaction = "{action $*}"; + dccownaction_target = "{action_core $0}%K:%b$1%n "; + + # DCC chat, others + dccmsg = "[%B$1-%K(%b$0%K)%n] "; + dccquerynick = "%B$*%n"; + dccaction = "%W (*dcc*) $*%n %|"; + + ## + ## statusbar + ## + + # background of statusbar + sb_background = "%0"; + + prompt = "%w$*%n%B:%W "; + + # default statusbar item style + sb = "%B[%W$*%B]%n"; + sbmode = " %b+%n$*"; + sbaway = " (%Baway%n)"; + sbservertag = ":%W$0"; + sbmore = "%_-- more --%_"; + sblag = "{sb L: %B$*}"; + sbmail = "{sb M: $*}"; + + # activity. Det is used for hilights when display doesn't support colors + sbact = "{sb {sbact_act $0}{sbact_det $1}}"; + sbact_act = "A: $*"; + sbact_det = " D: $*"; + + # usercount + sb_usercount = "{sb %W$0%n $1-}"; + sb_uc_ircops = "%_*%_%K/%R$*%n"; + sb_uc_ops = "%_@%_%K/%G$*%n"; + sb_uc_halfops = "%_=%_%K/%g$*%n"; + sb_uc_voices = "%_+%_%K/%Y$*%n"; + sb_uc_normal = "%_.%_%K/%W$*%n"; + sb_uc_space = " "; + +}; + +# %r%n%_$0%_$1%K |%n %| +formats = { + "fe-common/core" = { + pubmsg = "{pubmsgnick $2 {pubnick $[-16]0}}$1"; + join = " %_%Bjoin%_%K |%n %g{channick_hilight $0}%K!%n{chanhost_hilight $1}"; + part = " %_%Bpart%_%K |%n %W{channick $0}%K!%n{chanhost $1}: {reason $3}"; + kick = " %_%Bkick%_%K |%n %r{channick $0} %nby {nick $2} from {channel $1}: {reason $3}"; + quit = " %_%Bquit%_%K |%n %W{channick $0}%K!%n{chanhost $1}: {reason $2}"; + nick_changed = " %_%Bnick%_%K |%n {nick %w$0%n} %Nis now {nick %W$1%n}"; + endofnames = "{channel $0}: {hilight $1} nicks ({comment @/{hilight $2} +/{hilight $3} -/{hilight $4}})"; + own_msg = "{ownmsgnick $2 {ownnick $[-16]0}}$1"; + own_msg_channel = "{ownmsgnick $3 {ownnick $[-16]0}{msgchannel $1}}$2"; + pubmsg_me = "{pubmsgmenick $2 {menick $[-16]0}}$1"; + pubmsg_me_channel = "{pubmsgmenick $3 {menick $[-16]0}{msgchannel $1}}$2"; + pubmsg_hilight = "{pubmsghinick $0 $3 $[-16]1}$2"; + pubmsg_channel = "{pubmsgnick $3 {pubnick $[-16]0}{msgchannel $1}}$2"; + chanmode_change = " %_%Bmode%_%K |%n {$channel $0} %W{channick_hilight $2} %nsets mode %B{$mode $1}"; + channel_mode = " %_%Bmode%_%K |%n {$channel $0} %W{channick_hilight $2} %nsets mode %B{$mode $1}"; + }; + "fe-common/text" = { window_info_sticky = "%# Sticky : $0"; }; + "fe-common/irc" = { + chanmode_change = " %_%Bmode%_%K |%n %y{channick_hilight $2} %nsets mode %b{$mode $1} %non {$channelhilight $0}"; + whois = "{hilight $0} [{nickhost $1@$2}] [$whois_country]%: ircname : $3"; + server_chanmode_change = "{netsplit ServerMode}/{channelhilight $0}: {mode $1} by {nick $2}"; + whois_server = " server : $1 ({comment $2})"; + own_action = "{ownaction $0}%|$1"; + action_public = "{pubaction $0}%|$1"; + }; +}; diff --git a/.irssi/scripts/adv_windowlist.pl b/.irssi/scripts/adv_windowlist.pl new file mode 100644 index 0000000..839814e --- /dev/null +++ b/.irssi/scripts/adv_windowlist.pl @@ -0,0 +1,2988 @@ +use strict; +use warnings; + +our $VERSION = '1.11'; # 28b8dcf69e0355e +our %IRSSI = ( + authors => 'Nei', + contact => 'Nei @ anti@conference.jabber.teamidiot.de', + url => "http://anti.teamidiot.de/", + name => 'adv_windowlist', + description => 'Adds a permanent advanced window list on the right or in a status bar.', + sbitems => 'awl_shared', + license => 'GNU GPLv2 or later', + ); + +# UPGRADE NOTE +# ============ +# for users of 0.7 or earlier series, please note that appearance +# settings have moved to /format, i.e. inside your theme! +# the fifo (screen) has been replaced by an external viewer script + +# Usage +# ===== +# copy the script to ~/.irssi/scripts/ +# +# In irssi: +# +# /run adv_windowlist +# +# In your shell (for example a tmux split): +# +# perl ~/.irssi/scripts/adv_windowlist.pl +# +# To use sbar mode instead: +# +# /toggle awl_viewer +# +# Hint: to get rid of the old [Act:] display +# /statusbar window remove act +# +# to get it back: +# /statusbar window add -after lag -priority 10 act + +# Options +# ======= +# formats can be cleared with /format -delete +# +# /format awl_display_(no)key(_active|_visible) <string> +# * string : Format String for one window. The following $'s are expanded: +# $C : Name +# $N : Number of the Window +# $Q : meta-Keymap +# $H : Start hilighting +# $S : Stop hilighting +# /+++++++++++++++++++++++++++++++++, +# | **** I M P O R T A N T : **** | +# | | +# | don't forget to use $S if you | +# | used $H before! | +# | | +# '+++++++++++++++++++++++++++++++++/ +# key : a key binding that goes to this window could be detected in /bind +# nokey : no such key binding was detected +# active : window would receive the input you are currently typing +# visible : window is also visible on screen but not active (a split window) +# +# /format awl_name_display <string> +# * string : Format String for window names +# $0 : name as formatted by the settings +# +# /format awl_display_header <string> +# * string : Format String for this header line. The following $'s are expanded: +# $C : network tag +# +# /format awl_separator(2) <string> +# * string : Character to use between the channel entries +# variant 2 can be used for alternating separators (only in status bar +# without block display) +# +# /format awl_abbrev_chars <string> +# * string : Character to use when shortening long names. The second character +# will be used if two blocks need to be filled. +# +# /format awl_title <string> +# * string : Text to display in the title string or title bar +# +# /format awl_viewer_item_bg <string> +# * string : Format String specifying the viewer's item background colour +# +# /set awl_prefer_name <ON|OFF> +# * this setting decides whether awl will use the active_name (OFF) or the +# window name as the name/caption in awl_display_*. +# That way you can rename windows using /window name myownname. +# +# /set awl_hide_empty <num> +# * if visible windows without items should be hidden from the window list +# set it to 0 to show all windows +# 1 to hide visible windows without items (negative exempt +# active window) +# +# /set awl_custom_key_re <regex> +# * regex : which symbolic key names to show in $Q (for example F-keys) +# +# /set awl_detach <list> +# * list of windows that should be hidden from the window list. you +# can also use /awl detach and /awl attach to manage this +# setting. an optional data_level can be specified with ",num" +# +# /set awl_detach_data <num> +# * num : hide the detached window if its data_level is below num +# +# /set awl_detach_aht <ON|OFF> +# * if enabled, also detach all windows listed in the +# activity_hide_targets setting +# +# /set awl_hide_data <num> +# * num : hide the window if its data_level is below num +# set it to 0 to basically disable this feature, +# 1 if you don't want windows without activity to be shown +# 2 to show only those windows with channel text or hilight +# 3 to show only windows with hilight (negative exempt active window) +# +# /set awl_hide_name_data <num> +# * num : hide the name of the window if its data_level is below num +# (only works in status bar without block display) +# you will want to change your formats to add $H...$S around $Q or $N +# if you plan to use this +# +# /set awl_maxlines <num> +# * num : number of lines to use for the window list (0 to disable, negative +# lock) +# +# /set awl_maxcolumns <num> +# * num : number of columns to use for the window list when using the +# tmux integration (0 to disable) +# +# /set awl_block <num> +# * num : width of a column in viewer mode (negative values = block +# display in status bar mode) +# /+++++++++++++++++++++++++++++++++, +# | ****** W A R N I N G ! ****** | +# | | +# | If your block display looks | +# | DISTORTED, you need to add the | +# | following line to your .theme | +# | file under | +# | abstracts = { : | +# | | +# | sb_act_none = "%K$*"; | +# | | +# '+++++++++++++++++++++++++++++++++/ +# +# /set awl_sbar_maxlength <ON|OFF> +# * if you enable the maxlength setting, the block width will be used as a +# maximum length for the non-block status bar mode too. +# +# /set awl_height_adjust <num> +# * num : how many lines to leave empty in viewer mode +# +# /set awl_sort <-data_level|-last_line|refnum> +# * you can change the window sort order with this variable +# -data_level : sort windows with hilight first +# -last_line : sort windows in order of activity +# refnum : sort windows by window number +# active/server/tag : sort by server name +# lru : sort windows with the last recently used last +# "-" reverses the sort order +# typechecks are supported via ::, e.g. active::Query or active::Irc::Query +# undefinedness can be checked with ~, e.g. ~active +# string comparison can be done with =, e.g. name=(status) +# to make sort case insensitive, use #i, e.g. name#i +# any key in the window hash can be tested, e.g. active/chat_type=XMPP +# multiple criteria can be separated with , or +, e.g. -data_level+-last_line +# +# /set awl_placement <top|bottom> +# /set awl_position <num> +# * these settings correspond to /statusbar because awl will create +# status bars for you +# (see /help statusbar to learn more) +# +# /set awl_all_disable <ON|OFF> +# * if you set awl_all_disable to ON, awl will also remove the +# last status bar it created if it is empty. +# As you might guess, this only makes sense with awl_hide_data > 0 ;) +# +# /set awl_viewer <ON|OFF> +# * enable the external viewer script +# +# /set awl_viewer_launch <ON|OFF> +# * try to auto-launch the viewer under tmux or with a shell command +# /awl restart is required all auto-launch related settings to take +# effect +# +# /set awl_viewer_tmux_position <left|top|right|bottom|custom> +# * try to split in this direction when using tmux for the viewer +# custom : use custom_command setting +# +# /set awl_viewer_xwin_command <shell command> +# * custom command to run in order to start the viewer when irssi is +# running under X +# %A - gets replaced by the command to run the viewer +# %qA - additionally quote the command +# +# /set awl_viewer_custom_command <shell command> +# * custom command to run in order to start the viewer +# +# /set awl_viewer_launch_env <string> +# * specific environment settings for use on viewer auto-launch, +# without the AWL_ prefix +# +# /set awl_shared_sbar <left<right|OFF> +# * share a status bar for the first awl item, you will need to manually +# /statusbar window add -after lag -priority 10 awl_shared +# left : space in cells occupied on the left of status bar +# right : space occupied on the right +# Note: you need to replace "left" AND "right" with the appropriate numbers! +# +# /set awl_path <path> +# * path to the file which the viewer script reads +# +# /set fancy_abbrev <no|head|strict|fancy> +# * how to shorten too long names +# no : shorten in the middle +# head : always cut off the ends +# strict : shorten repeating substrings +# fancy : combination of no+strict +# +# /set awl_custom_xform <perl code> +# * specify a custom routine to transform window names +# example: s/^#// remove the #-mark of IRC channels +# the special flags $CHANNEL / $TAG / $QUERY / $NAME can be +# tested in conditionals +# +# /set awl_last_line_shade <timeout> +# * set timeout to shade activity base colours, to enable +# you also need to add +-last_line to awl_sort +# (requires 256 colour support) +# +# /set awl_no_mode_hint <ON|OFF> +# * whether to show the hint of running the viewer script in the +# status bar +# +# /set awl_mouse <ON|OFF> +# * enable the terminal mouse in irssi +# (use the awl-patched mouse.pl for gestures and commands if you need +# them and disable mouse_escape) +# +# /set awl_mouse_offset <num> +# * specifies where on the screen is the awl status bar +# (0 = on top/bottom, 1 = one additional line in between, +# e.g. prompt) +# you MUST set this correctly otherwise the mouse coordinates will +# be off +# +# /set mouse_scroll <num> +# * how many lines the mouse wheel scrolls +# +# /set mouse_escape <num> +# * seconds to disable the mouse, when not clicked on the windowlist +# + +# Commands +# ======== +# /awl detach <num> +# * hide the current window from the window list. num specifies the +# data_level (optional) +# +# /awl attach +# * unhide the current window from the window list +# +# /awl ack +# * change to the next window with activity, ignoring detached windows +# +# /awl redraw +# * redraws the windowlist. There may be occasions where the +# windowlist can get destroyed so you can use this command to +# force a redraw. +# +# /awl restart +# * restart the connection to the viewer script. + +# Viewer script +# ============= +# When run from the command line, adv_windowlist acts as the viewer +# script to be used together with the irssi script to display the +# window list in a sidebar/terminal of its own. +# +# One optional parameter is accepted, the awl_path +# +# The viewer can be configured by three environment variables: +# +# AWL_HI9=1 +# * interpret %9 as high-intensity toggle instead of bold. This had +# been the default prior to version 0.9b8 +# +# AWL_AUTOFOCUS=0 +# * disable auto-focus behaviour when activating a window +# +# AWL_NOTITLE=1 +# * disable the title bar + +# Nei =^.^= ( anti@conference.jabber.teamidiot.de ) + +no warnings 'redefine'; +use constant IN_IRSSI => __PACKAGE__ ne 'main' || $ENV{IRSSI_MOCK}; +use constant SCRIPT_FILE => __FILE__; +no if !IN_IRSSI, strict => (qw(subs refs)); +use if IN_IRSSI, Irssi => (); +use if IN_IRSSI, 'Irssi::TextUI' => (); +use v5.10; +use Encode; +use Storable (); +use IO::Socket::UNIX; +use List::Util qw(min max reduce); +use Hash::Util qw(lock_keys); +use Text::ParseWords qw(shellwords); + +BEGIN { + if ($] < 5.012) { + *CORE::GLOBAL::length = *CORE::GLOBAL::length = sub (_) { + defined $_[0] ? CORE::length($_[0]) : undef + }; + } + *Irssi::active_win = {}; # hide incorrect warning +} + +unless (IN_IRSSI) { + local *_ = \@ARGV; + &AwlViewer::main; + exit; +} + + +use constant GLOB_QUEUE_TIMER => 100; + +our $BLOCK_ALL; # localized blocker +my @actString; # status bar texts +my @win_items; +my $currentLines = 0; +my %awins; +my $globTime; # timer to limit remake calls + +my %CHANGED; +my $VIEWER_MODE; +my $MOUSE_ON; +my %mouse_coords; +my %statusbars; +my %S; # settings +my $settings_str = '1'; +my $window_sort_func; +my $custom_xform; +my $custom_key_re = qr/(?!)/; +my ($sb_base_width, $sb_base_width_pre, $sb_base_width_post); +my $print_text_activity; +my $shade_line_timer; +my ($screenHeight, $screenWidth); +my %viewer; + +my (%keymap, %nummap, %wnmap, %specialmap, %wnmap_exp, %custom_key_map); +my %banned_channels; +my %detach_map; +my %abbrev_cache; + +use constant setc => 'awl'; + +sub set ($) { + setc . '_' . $_[0] +} + +sub add_statusbar { + for (@_) { + # add subs + my $l = set $_; + { + my $close = $_; + no strict 'refs'; + *{$l} = sub { awl($close, @_) }; + } + Irssi::command("^statusbar $l reset"); + Irssi::command("statusbar $l enable"); + if (lc $S{placement} eq 'top') { + Irssi::command("statusbar $l placement top"); + } + if (my $x = $S{position}) { + Irssi::command("statusbar $l position $x"); + } + Irssi::command("statusbar $l add -priority 100 -alignment left barstart"); + Irssi::command("statusbar $l add $l"); + Irssi::command("statusbar $l add -priority 100 -alignment right barend"); + Irssi::command("statusbar $l disable"); + Irssi::statusbar_item_register($l, '$0', $l); + $statusbars{$_} = 1; + Irssi::command("statusbar $l enable"); + } +} + +sub remove_statusbar { + for (@_) { + my $l = set $_; + Irssi::command("statusbar $l disable"); + Irssi::command("statusbar $l reset"); + Irssi::statusbar_item_unregister($l); + { + no strict 'refs'; + undef &{$l}; + } + delete $statusbars{$_}; + } +} + +my $awl_shared_empty = sub { + return if $BLOCK_ALL; + my ($item, $get_size_only) = @_; + $item->default_handler($get_size_only, '', '', 0); +}; + +sub syncLines { + my $maxLines = $S{maxlines}; + my $newLines = ($maxLines > 0 and @actString > $maxLines) ? + $maxLines : + ($maxLines < 0) ? + -$maxLines : + @actString; + $currentLines = 1 if !$currentLines && $S{shared_sbar}; + if ($S{shared_sbar} && !$statusbars{shared}) { + my $l = set 'shared'; + { + no strict 'refs'; + *{$l} = sub { + return if $BLOCK_ALL; + my ($item, $get_size_only) = @_; + + my $text = $actString[0]; + my $title = _get_format(set 'title'); + if (length $title) { + $title =~ s{\\(.)|(.)}{ + defined $2 ? quotemeta $2 + : $1 eq 'V' ? '\u' + : $1 eq ':' ? quotemeta ':%n' + : $1 =~ /^[uUFQE]$/ ? "\\$1" + : quotemeta "\\$1" + }sge; + $title = eval qq{"$title"}; + $title .= ' '; + } + my $pat = defined $text ? "{sb $title\$*}" : '{sb }'; + $text //= ''; + $item->default_handler($get_size_only, $pat, $text, 0); + }; + } + $statusbars{shared} = 1; + remove_statusbar (0) if $statusbars{0}; + } + elsif ($statusbars{shared} && !$S{shared_sbar}) { + add_statusbar (0) if $currentLines && $newLines; + delete $statusbars{shared}; + my $l = set 'shared'; + { + no strict 'refs'; + *{$l} = $awl_shared_empty; + } + } + if ($currentLines == $newLines) { return; } + elsif ($newLines > $currentLines) { + add_statusbar ($currentLines .. ($newLines - 1)); + } + else { + remove_statusbar (reverse ($newLines .. ($currentLines - 1))); + } + $currentLines = $newLines; +} + +sub awl { + return if $BLOCK_ALL; + my ($line, $item, $get_size_only) = @_; + + my $text = $actString[$line]; + my $pat = defined $text ? '{sb $*}' : '{sb }'; + $text //= ''; + $item->default_handler($get_size_only, $pat, $text, 0); +} + +# remove old statusbars +{ my %killBar; + sub get_old_status { + my ($textDest, $cont, $cont_stripped) = @_; + if ($textDest->{level} == MSGLEVEL_CLIENTCRAP and $textDest->{target} eq '' and !defined $textDest->{server}) { + my $name = quotemeta(set ''); + if ($cont_stripped =~ m/^$name(\d+)\s/) { $killBar{$1} = 1; } + Irssi::signal_stop; + } + } + sub killOldStatus { + %killBar = (); + Irssi::signal_add_first('print text' => 'get_old_status'); + Irssi::command('statusbar'); + Irssi::signal_remove('print text' => 'get_old_status'); + remove_statusbar(keys %killBar); + } +} + +sub _add_map { + my ($type, $target, $map) = @_; + ($type->{$target}) = sort { length $a <=> length $b || $a cmp $b } + $map, exists $type->{$target} ? $type->{$target} : (); +} + +sub get_keymap { + my ($textDest, undef, $cont_stripped) = @_; + if ($textDest->{level} == MSGLEVEL_CLIENTCRAP and $textDest->{target} eq '' and !defined $textDest->{server}) { + my $one_meta_or_ctrl_key = qr/((?:meta-)*?)(?:(meta-|\^)(\S)|(\w+))/; + $cont_stripped = as_uni($cont_stripped); + if ($cont_stripped =~ m/((?:$one_meta_or_ctrl_key-)*$one_meta_or_ctrl_key)\s+(.*)$/) { + my ($combo, $command) = ($1, $10); + my $map = ''; + while ($combo =~ s/(?:-|^)$one_meta_or_ctrl_key$//) { + my ($level, $ctl, $key, $nkey) = ($1, $2, $3, $4); + my $numlevel = ($level =~ y/-//); + if (not defined $key and $nkey =~ /^($custom_key_re)$/) { + $key = $nkey; + } + $ctl = '' if !$ctl || $ctl ne '^'; + $map = ('-' x ($numlevel%2)) . ('+' x ($numlevel/2)) . + $ctl . (defined $key ? $key : "\01$nkey\01") . $map; + } + for ($command) { + last unless length $map; + if (/^change_window (\d+)/i) { + _add_map(\%nummap, $1, $map); + } + elsif (/^(?:command window goto|change_window) (\S+)/i) { + my $window = $1; + if ($window !~ /\D/) { + _add_map(\%nummap, $window, $map); + } + elsif (lc $window eq 'active') { + _add_map(\%specialmap, '_active', $map); + } + else { + _add_map(\%wnmap, $window, $map); + } + } + elsif (/^(?:active_window|command ((awl )?ack))/i) { + _add_map(\%specialmap, '_active', $map); + $viewer{use_ack} = $1; + } + elsif (/^command window last/i) { + _add_map(\%specialmap, '_last', $map); + } + elsif (/^(?:upper_window|command window up)/i) { + _add_map(\%specialmap, '_up', $map); + } + elsif (/^(?:lower_window|command window down)/i) { + _add_map(\%specialmap, '_down', $map); + } + elsif (/^key\s+(\w+)/i) { + $custom_key_map{$1} = $map; + } + } + } + Irssi::signal_stop; + } +} + +sub update_keymap { + %nummap = %wnmap = %specialmap = %custom_key_map = (); + Irssi::signal_remove('command bind' => 'watch_keymap'); + Irssi::signal_add_first('print text' => 'get_keymap'); + Irssi::command('bind'); + Irssi::signal_remove('print text' => 'get_keymap'); + for (keys %custom_key_map) { + if (exists $custom_key_map{$_} && + $custom_key_map{$_} =~ s/\01(\w+)\01/exists $custom_key_map{$1} ? $custom_key_map{$1} : "\02"/ge) { + if ($custom_key_map{$_} =~ /\02/) { + delete $custom_key_map{$_}; + } + else { + redo; + } + } + } + for my $keymap (\(%specialmap, %wnmap, %nummap)) { + for (keys %$keymap) { + if ($keymap->{$_} =~ s/\01(\w+)\01/exists $custom_key_map{$1} ? $custom_key_map{$1} : "\02"/ge) { + if ($keymap->{$_} =~ /\02/) { + delete $keymap->{$_}; + } + } + } + } + Irssi::signal_add('command bind' => 'watch_keymap'); + delete $viewer{client_keymap}; + &wl_changed; +} + +# watch keymap changes +sub watch_keymap { + Irssi::timeout_add_once(1000, 'update_keymap', undef); +} + +{ my %strip_table = ( + # fe-common::core::formats.c:format_expand_styles + # delete format_backs format_fores bold_fores other stuff + (map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8I:|FnN>#[' . 'pP')), + # escape + (map { $_ => $_ } (split //, '{}%')), + ); + sub ir_strip_codes { # strip %codes + my $o = shift; + $o =~ s/(%(%|Z.{6}|z.{6}|X..|x..|.))/exists $strip_table{$2} ? $strip_table{$2} : + $2 =~ m{x(?:0[a-f]|[1-6][0-9a-z]|7[a-x])|z[0-9a-f]{6}}i ? '' : $1/gex; + $o + } +} +## ir_parse_special -- wrapper around parse_special +## $i - input format +## $args - array ref of arguments to format +## $win - different target window (default current window) +## $flags - different kind of escape flags (default 4|8) +## returns formatted str +sub ir_parse_special { + my $o; + my $i = shift; + my $args = shift // []; + y/ /\177/ for @$args; # hack to escape spaces + my $win = shift || Irssi::active_win; + my $flags = shift // 0x4|0x8; + my @cmd_args = ($i, (join ' ', @$args), $flags); + my $server = Irssi::active_server(); + if (ref $win and ref $win->{active}) { + $o = $win->{active}->parse_special(@cmd_args); + } + elsif (ref $win and ref $win->{active_server}) { + $o = $win->{active_server}->parse_special(@cmd_args); + } + elsif (ref $server) { + $o = $server->parse_special(@cmd_args); + } + else { + $o = &Irssi::parse_special(@cmd_args); + } + $o =~ y/\177/ /; + $o +} + +sub sb_format_expand { # Irssi::current_theme->format_expand wrapper + Irssi::current_theme->format_expand( + $_[0], + ( + Irssi::EXPAND_FLAG_IGNORE_REPLACES + | + ($_[1] ? 0 : Irssi::EXPAND_FLAG_IGNORE_EMPTY) + ) + ) +} + +{ my $term_type = Irssi::version > 20040819 ? 'term_charset' : 'term_type'; + if (Irssi->can('string_width')) { + *screen_length = sub { Irssi::string_width($_[0]) }; + } + else { + local $@; + eval { require Text::CharWidth; }; + unless ($@) { + *screen_length = sub { Text::CharWidth::mbswidth($_[0]) }; + } + else { + my $err = $@; chomp $err; $err =~ s/\sat .* line \d+\.$//; + #Irssi::print("%_$IRSSI{name}: warning:%_ Text::CharWidth module failed to load. Length calculation may be off! Error was:"); + print "%_$IRSSI{name}:%_ $err"; + *screen_length = sub { + my $temp = shift; + if (lc Irssi::settings_get_str($term_type) eq 'utf-8') { + Encode::_utf8_on($temp); + } + length($temp) + }; + } + } + sub as_uni { + no warnings 'utf8'; + Encode::decode(Irssi::settings_get_str($term_type), $_[0], 0) + } + sub as_tc { + Encode::encode(Irssi::settings_get_str($term_type), $_[0], 0) + } +} + +sub sb_length { + screen_length(ir_strip_codes($_[0])) +} + +sub run_custom_xform { + local $@; + eval { + $custom_xform->() + }; + if ($@) { + $@ =~ /^(.*)/; + print '%_'.(set 'custom_xform').'%_ died (disabling): '.$1; + $custom_xform = undef; + } +} + +sub remove_uniform { + my $o = shift; + $o =~ s/^xmpp:(.*?[%@]).+\.[^.]+$/$1/ or + $o =~ s#^psyc://.+\.[^.]+/([@~].*)$#$1#; + if ($custom_xform) { + run_custom_xform() for $o; + } + $o +} + +sub remove_uniform_vars { + my $win = shift; + my $name = __PACKAGE__ . '::custom_xform::' . $win->{active}{type} + if ref $win->{active} && $win->{active}{type}; + no strict 'refs'; + local ${$name} = 1 if $name; + remove_uniform(+shift); +} + +sub lc1459 { + my $x = shift; + $x =~ y/][\\^/}{|~/; + lc $x +} + +sub window_list { + my $i = 0; + map { $_->[1] } sort $window_sort_func map { [ $i++, $_ ] } Irssi::windows; +} + +sub _calculate_abbrev { + my ($wins, $abbrevList) = @_; + if ($S{fancy_abbrev} !~ /^(no|off|head)/i) { + my @nameList = map { ref $_ ? remove_uniform_vars($_, as_uni($_->get_active_name) // '') : '' } @$wins; + for (my $i = 0; $i < @nameList - 1; ++$i) { + my ($x, $y) = ($nameList[$i], $nameList[$i + 1]); + s/^[+#!=]// for $x, $y; + my $res = exists $abbrev_cache{$x}{$y} ? $abbrev_cache{$x}{$y} + : $abbrev_cache{$x}{$y} = string_LCSS($x, $y); + if (defined $res) { + for ($nameList[$i], $nameList[$i + 1]) { + $abbrevList->{$_} //= int((index $_, $res) + (length $res) / 2); + } + } + } + } +} + +my %act_last_line_shades = ( + r => [qw[ 50 40 30 20 ]], + g => [qw[ 1O 1I 1C 16 ]], + y => [qw[ 5O 4I 3C 26 ]], + b => [qw[ 15 14 13 12 ]], + m => [qw[ 54 43 32 21 ]], + c => [qw[ 1S 1L 1E 17 ]], + w => [qw[ 7W 7T 7Q 3E ]], + K => [qw[ 7M 7K 27 7H ]], + R => [qw[ 60 50 40 30 ]], + G => [qw[ 1U 1O 1I 1C ]], + Y => [qw[ 6U 5O 4I 3C ]], + B => [qw[ 2B 2A 29 28 ]], + M => [qw[ 65 54 43 32 ]], + C => [qw[ 1Z 1S 1L 1E ]], + W => [qw[ 6Z 5S 7R 7O ]], + ); + +sub _format_display { + my (undef, $format, $cformat, $hilight, $name, $number, $key, $win) = @_; + if ($print_text_activity && $S{line_shade}) { + my @hilight_code = split /\177/, sb_format_expand("{$hilight \177}"), 2; + my $max_time = max(1, log($S{line_shade}) - log(1000)); + my $time_delta = min(3, min($max_time, log(max(1, time - $win->{last_line}))) / $max_time * 3); + if ($hilight_code[0] =~ /%(.)/ && exists $act_last_line_shades{$1}) { + $hilight = 'sb_act_hilight_color %X'.$act_last_line_shades{$1}[$time_delta]; + } + } + $cformat = '$0' unless length $cformat; + my %map = ('$C' => $cformat, '$N' => '$1', '$Q' => '$2'); + $format =~ s<(\$.)><$map{$1}//$1>ge; + $format =~ s<\$H((?:\$.|[^\$])*?)\$S><{$hilight $1%n}>g; + my @ret = ir_parse_special(sb_format_expand($format), [$name, $number, $key], $win); + @ret +} + +sub _get_format { + Irssi::current_theme->get_format(__PACKAGE__, @_) +} + +sub _is_detached { + my ($win, $active_number) = @_; + my $level = $win->{data_level} // 0; + my $number = $win->{refnum}; + my $name = lc1459( as_uni($win->{name}) ); + my $active = lc1459( as_uni($win->get_active_name) // '' ); + my $tag = $win->{active} && $win->{active}{server} ? lc1459( as_uni($win->{active}{server}{tag}) // '' ) : ''; + my @cond = ($number); + push @cond, "$name" if length $name; + push @cond, "$tag/$active" if length $tag && length $active; + push @cond, "$active" if length $active; + push @cond, "$tag/*", "$tag/::all" if length $tag; + push @cond, "*", "::all"; + for my $cond (@cond) { + if (exists $detach_map{ $cond }) { + my $dd = $detach_map{ $cond } // $S{detach_data}; + return $win->{data_level} < abs $dd + && ($number != $active_number || 0 <= $dd); + } + } + return; +} + +sub _calculate_items { + my ($wins, $abbrevList) = @_; + + my $display_header = _get_format(set 'display_header'); + my $name_format = _get_format(set 'name_display'); + my $abbrev_chars = as_uni(_get_format(set 'abbrev_chars')); + + my %displays; + + my $active = Irssi::active_win; + @win_items = (); + %keymap = (%nummap, %wnmap_exp); + + my ($numPad, $keyPad) = (0, 0); + if ($VIEWER_MODE or $S{block} < 0) { + $numPad = length((sort { length $b <=> length $a } keys %keymap)[0]) // 0; + $keyPad = length((sort { length $b <=> length $a } values %keymap)[0]) // 0; + } + my $last_net; + my ($abbrev1, $abbrev2) = $abbrev_chars =~ /(\X)(.*)/; + my @abbrev_chars = ('~', "\x{301c}"); + unless (defined $abbrev1 && screen_length(as_tc($abbrev1)) == 1) { $abbrev1 = $abbrev_chars[0] } + unless (length $abbrev2) { + $abbrev2 = $abbrev1; + if ($abbrev1 eq $abbrev_chars[0]) { + $abbrev2 = $abbrev_chars[1]; + } + else { + $abbrev2 = $abbrev1; + } + } + if (screen_length(as_tc($abbrev2)) == 1) { + $abbrev2 x= 2; + } + while (screen_length(as_tc($abbrev2)) > 2) { + chop $abbrev2; + } + unless (screen_length(as_tc($abbrev2)) == 2) { + $abbrev2 = $abbrev_chars[1]; + } + for my $win (@$wins) { + my $global_tag_header_mode; + + next unless ref $win; + + my $backup_win = Storable::dclone($win); + delete $backup_win->{active} unless ref $backup_win->{active}; + + $global_tag_header_mode = + $display_header && ($last_net // '') ne ($backup_win->{active}{server}{tag} // ''); + + if ($win->{data_level} < abs $S{hide_data} + && ($win->{refnum} != $active->{refnum} || 0 <= $S{hide_data})) { + next; } + elsif (exists $awins{$win->{refnum}} && $S{hide_empty} && !$win->items + && ($win->{refnum} != $active->{refnum} || 0 <= $S{hide_empty})) { + next; } + elsif (_is_detached($win, $active->{refnum})) { + next; } + + my $colour = $win->{hilight_color} // ''; + my $hilight = do { + if ($win->{data_level} == 0) { 'sb_act_none'; } + elsif ($win->{data_level} == 1) { 'sb_act_text'; } + elsif ($win->{data_level} == 2) { 'sb_act_msg'; } + elsif ($colour ne '') { "sb_act_hilight_color $colour"; } + elsif ($win->{data_level} == 3) { 'sb_act_hilight'; } + else { 'sb_act_special'; } + }; + my $number = $win->{refnum}; + + my ($name, $display, $cdisplay); + if ($global_tag_header_mode) { + $display = $display_header; + $name = as_uni($backup_win->{active}{server}{tag}) // ''; + if ($custom_xform) { + no strict 'refs'; + local ${ __PACKAGE__ . '::custom_xform::TAG' } = 1; + run_custom_xform() for $name; + } + } + else { + my @display = ('display_nokey'); + if (defined $keymap{$number} and $keymap{$number} ne '') { + unshift @display, map { (my $cpy = $_) =~ s/_no/_/; $cpy } @display; + } + if (exists $awins{$number}) { + unshift @display, map { my $cpy = $_; $cpy .= '_visible'; $cpy } @display; + } + if ($active->{refnum} == $number) { + unshift @display, map { my $cpy = $_; $cpy .= '_active'; $cpy } + grep { !/_visible$/ } @display; + } + $display = (grep { length $_ } + map { $displays{$_} //= _get_format(set $_) } + @display)[0]; + $cdisplay = $name_format; + $name = as_uni($win->get_active_name) // ''; + $name = '*' if $S{banned_on} and exists $banned_channels{lc1459($name)}; + $name = remove_uniform_vars($win, $name) if $name ne '*'; + if ($name ne '*' and $win->{name} ne '' and $S{prefer_name}) { + $name = as_uni($win->{name}); + if ($custom_xform) { + no strict 'refs'; + local ${ __PACKAGE__ . '::custom_xform::NAME' } = 1; + run_custom_xform() for $name; + } + } + + if (!$VIEWER_MODE && $S{block} >= 0 && $S{hide_name} + && $win->{data_level} < abs $S{hide_name} + && ($win->{refnum} != $active->{refnum} || 0 <= $S{hide_name})) { + $name = ''; + $cdisplay = ''; + } + } + + $display = "$display%n"; + my $num_ent = (' 'x max(0,$numPad - length $number)) . $number; + my $key_ent = exists $keymap{$number} ? ((' 'x max(0,$keyPad - length $keymap{$number})) . $keymap{$number}) : ' 'x$keyPad; + if ($VIEWER_MODE or $S{sbar_maxlen} or $S{block} < 0) { + my $baseLength = sb_length(_format_display( + '', $display, $cdisplay, $hilight, + 'x', # placeholder + $num_ent, + $key_ent, + $win)) - 1; + my $diff = (abs $S{block}) - (screen_length(as_tc($name)) + $baseLength); + if ($diff < 0) { # too long + my $screen_length = screen_length(as_tc($name)); + if ((abs $diff) >= $screen_length) { $name = '' } # forget it + elsif ((abs $diff) + screen_length(as_tc(substr($name, 0, 1))) >= $screen_length) { $name = substr($name, 0, 1); } + else { + my $ulen = length $name; + my $middle2 = exists $abbrevList->{$name} ? + ($S{fancy_strict}) ? + 2* $abbrevList->{$name} : + (2*($abbrevList->{$name} + $ulen) / 3) : + ($S{fancy_head}) ? + 2*$ulen : + $ulen; + my $first = 1; + while (length $name > 1) { + my $cp = $middle2 >= 0 ? $middle2/2 : -1; # clearing position + my $rm = 2; + # if character at end is wider than 1 cell -> replace it with ~ + if (screen_length(as_tc(substr $name, $cp, 1)) > 1) { + if ($first || $cp < 0) { + $rm = 1; + $first = undef; + } + } + elsif ($cp < 0) { # elsif at end -> replace last 2 characters + --$cp; + } + (substr $name, $cp, $rm) = $abbrev1; + if ($cp > -1 && $rm > 1) { + --$middle2; + } + my $sl = screen_length(as_tc($name)); + if ($sl + $baseLength < abs $S{block}) { + (substr $name, ($middle2+1)/2, 1) = $abbrev2; + last; + } + elsif ($sl + $baseLength == abs $S{block}) { + last; + } + } + } + } + elsif ($VIEWER_MODE or $S{block} < 0) { + $name .= (' ' x $diff); + } + } + + push @win_items, _format_display( + '', $display, $cdisplay, $hilight, + as_tc($name), + $num_ent, + as_tc($key_ent), + $win); + + if ($global_tag_header_mode) { + $last_net = $backup_win->{active}{server}{tag}; + redo; + } + + $mouse_coords{refnum}{$#win_items} = $number; + } +} + +sub _spread_items { + my $width = $screenWidth - $sb_base_width - 1; + my @separator = _get_format(set 'separator'); + if ($S{block} >= 0) { + my $sep2 = _get_format(set 'separator2'); + push @separator, $sep2 if length $sep2 && $sep2 ne $separator[0]; + } + $separator[0] .= '%n'; + my @sepLen = map { sb_length($_) } @separator; + + @actString = (); + my $curLine; + my $curLen = 0; + if ($S{shared_sbar}) { + $curLen += $S{shared_sbar}[0] + 2; + $width -= $S{shared_sbar}[2]; + } + my $mouse_header_check = 0; + for my $it (@win_items) { + my $itemLen = sb_length($it); + if ($curLen) { + if ($curLen + $itemLen + $sepLen[$mouse_header_check % @sepLen] > $width) { + $width += $S{shared_sbar}[2] + if !@actString && $S{shared_sbar}; + push @actString, $curLine; + $curLine = undef; + $curLen = 0; + } + elsif (defined $curLine) { + $curLine .= $separator[$mouse_header_check % @separator]; + $curLen += $sepLen[$mouse_header_check % @sepLen]; + } + } + $curLine .= $it; + if (exists $mouse_coords{refnum}{$mouse_header_check}) { + $mouse_coords{scalar @actString}{ $_ } = $mouse_coords{refnum}{$mouse_header_check} + for $curLen .. $curLen + $itemLen - 1; + } + $curLen += $itemLen; + } + continue { + ++$mouse_header_check; + } + $curLen -= $S{shared_sbar}[0] + if !@actString && $S{shared_sbar}; + push @actString, $curLine if $curLen; +} + +sub remake { + my %abbrevList; + my @wins = window_list(); + if ($VIEWER_MODE or $S{sbar_maxlen} or $S{block} < 0) { + _calculate_abbrev(\@wins, \%abbrevList); + } + + %mouse_coords = ( refnum => +{} ); + _calculate_items(\@wins, \%abbrevList); + + unless ($VIEWER_MODE) { + _spread_items(); + + push @actString, undef unless @actString || $S{all_disable}; + } +} + +sub update_wl { + return if $BLOCK_ALL; + remake(); + + Irssi::statusbar_items_redraw(set $_) for keys %statusbars; + + unless ($VIEWER_MODE) { + Irssi::timeout_add_once(100, 'syncLines', undef); + } + else { + syncViewer(); + } +} + +sub screenFullRedraw { + my ($window) = @_; + if (!ref $window or $window->{refnum} == Irssi::active_win->{refnum}) { + $viewer{fullRedraw} = 1 if $viewer{client}; + $settings_str = ''; + &setup_changed; + } +} + +sub restartViewerServer { + if ($VIEWER_MODE) { + stop_viewer(); + start_viewer(); + } +} + +sub _simple_quote { + my @r = map { + my $x = $_; + $x =~ s/'/'"'"'/g; + $x = "'$x'"; + } @_; + wantarray ? @r : shift @r +} + +sub _viewer_command_replace_format { + my ($ecmd, @args) = @_; + my $file = _simple_quote(SCRIPT_FILE()); + my $path = _simple_quote($viewer{path}); + my @env; + for my $env (shellwords($S{viewer_launch_env})) { + if ($env =~ /^(\w+)(?:=(.*))$/) { + push @env, "AWL_$1=$2" + } + } + my $cmd = join ' ', + (@env ? ('env', _simple_quote(@env)) : ()), + 'perl', $file, '-1', _simple_quote(@args), $path; + $ecmd =~ s{%(%|\w+)}{ + my $sub = $1; + if ($sub eq '%') { + '%' + } + elsif ($sub =~ /^(q*)A(.*)/) { + my $ret = $cmd; + for (1..length $1) { + $ret = _simple_quote($ret); + } + "$ret$2" + } + else { + "%$sub" + } + }gex; + $ecmd +} + +sub start_viewer { + unlink $viewer{path} if -S $viewer{path} || -p _; + + $viewer{server} = IO::Socket::UNIX->new( + Type => SOCK_STREAM, + Local => $viewer{path}, + Listen => 1 + ); + unless ($viewer{server}) { + $viewer{msg} = "Viewer: $!"; + $viewer{retry} = Irssi::timeout_add_once(5000, 'retry_viewer', 1); + return; + } + $viewer{server}->blocking(0); + set_viewer_mode_hint(); + $viewer{server_tag} = Irssi::input_add($viewer{server}->fileno, INPUT_READ, 'vi_connected', undef); + + if ($S{viewer_launch}) { + if (length $ENV{TMUX_PANE} && length $ENV{TMUX} && lc $S{viewer_tmux_position} ne 'custom') { + my $cmd = _viewer_command_replace_format('%qA', '-p', lc $S{viewer_tmux_position}); + Irssi::command("exec - tmux neww -d $cmd 2>&1 &"); + } + elsif (length $ENV{WINDOWID} && length $ENV{DISPLAY} && length $S{viewer_xwin_command} && $S{viewer_xwin_command} =~ /\S/) { + my $cmd = _viewer_command_replace_format($S{viewer_xwin_command}); + Irssi::command("exec - $cmd 2>&1 &"); + } + elsif (length $S{viewer_custom_command} && $S{viewer_custom_command} =~ /\S/) { + my $cmd = _viewer_command_replace_format($S{viewer_custom_command}); + Irssi::command("exec - $cmd 2>&1 &"); + } + } +} + +sub set_viewer_mode_hint { + return unless $viewer{server}; + if ($S{no_mode_hint}) { + $viewer{msg} = undef; + } + else { + my ($name) = __PACKAGE__ =~ /::([^:]+)$/; + $viewer{msg} = "Run $name from the shell or switch to sbar mode"; + } +} + +sub retry_viewer { + start_viewer(); +} + +sub vi_close_client { + Irssi::input_remove(delete $viewer{client_tag}) if exists $viewer{client_tag}; + $viewer{client}->close if $viewer{client}; + delete $viewer{client}; + delete $viewer{client_keymap}; + delete $viewer{client_settings}; + delete $viewer{client_env}; + delete $viewer{fullRedraw}; +} + +sub vi_connected { + vi_close_client(); + $viewer{client} = $viewer{server}->accept or return; + $viewer{client}->blocking(0); + $viewer{client_tag} = Irssi::input_add($viewer{client}->fileno, INPUT_READ, 'vi_clientinput', undef); + syncViewer(); +} + +use constant VIEWER_BLOCK_SIZE => 1024; +sub vi_clientinput { + if ($viewer{client}->read(my $buf, VIEWER_BLOCK_SIZE)) { + $viewer{rcvbuf} .= $buf; + if ($viewer{rcvbuf} =~ s/^(?:(active|\d+)|(last|up|down))\n//igm) { + if (defined $2) { + Irssi::command("window $2"); + } + elsif (lc $1 eq 'active' && $viewer{use_ack}) { + Irssi::command($viewer{use_ack}); + } + else { + Irssi::command("window goto $1"); + } + } + } + else { + vi_close_client(); + Irssi::timeout_add_once(100, 'syncViewer', undef); + } +} + +sub stop_viewer { + Irssi::timeout_remove(delete $viewer{retry}) if exists $viewer{retry}; + vi_close_client(); + Irssi::input_remove(delete $viewer{server_tag}) if exists $viewer{server_tag}; + return unless $viewer{server}; + $viewer{server}->close; + delete $viewer{server}; +} +sub _encode_var { + my $str; + while (@_) { + my ($name, $var) = splice @_, 0, 2; + my $type = ref $var ? $var =~ /HASH/ ? 'map' : $var =~ /ARRAY/ ? 'list' : '' : ''; + $str .= "\n\U$name$type\_begin\n"; + if ($type eq 'map') { + no warnings 'numeric'; + $str .= " $_\n ${$var}{$_}\n" for sort { $a <=> $b || $a cmp $b } keys %$var; + } + elsif ($type eq 'list') { + $str .= " $_\n" for @$var; + } + else { + $str .= " $var\n"; + } + $str .= "\U$name$type\_end\n"; + } + $str +} +sub syncViewer { + if ($viewer{client}) { + @actString = (); + if ($currentLines) { + killOldStatus(); + $currentLines = 0; + } + my $str; + unless ($viewer{client_keymap}) { + $str .= _encode_var('key', +{ %nummap, %specialmap }); + $viewer{client_keymap} = 1; + } + unless ($viewer{client_settings}) { + $str .= _encode_var( + block => $S{block}, + ha => $S{height_adjust}, + mc => $S{maxcolumns}, + ml => $S{maxlines}, + tc => $S{true_colour}, + ); + $viewer{client_settings} = 1; + } + unless ($viewer{client_env}) { + $str .= _encode_var(irssienv => +{ + length $ENV{TMUX_PANE} && length $ENV{TMUX} ? + (tmux_pane => $ENV{TMUX_PANE}, + tmux_srv => $ENV{TMUX}) : (), + length $ENV{WINDOWID} ? + (xwinid => $ENV{WINDOWID}) : (), + }); + $viewer{client_env} = 1; + } + my $separator = _get_format(set 'separator'); + my $sepLen = sb_length($separator); + my $item_bg = _get_format(set 'viewer_item_bg'); + my $title = _get_format(set 'title'); + if (length $title) { + $title =~ s{\\(.)|(.)}{ + defined $2 ? quotemeta $2 + : $1 eq 'V' ? '\U' + : $1 eq ':' ? quotemeta '%N' + : $1 =~ /^[uUFQE]$/ ? "\\$1" + : quotemeta "\\$1" + }sge; + $title = eval qq{"$title"}; + } + $str .= _encode_var(redraw => 1) if delete $viewer{fullRedraw}; + $str .= _encode_var(separator => $separator, + seplen => $sepLen, + itembg => $item_bg, + title => $title, + mouse => $mouse_coords{refnum}, + key2 => \%wnmap_exp, + win => \@win_items); + + my $was = $viewer{client}->blocking(1); + $viewer{client}->print($str); + $viewer{client}->blocking($was); + } + elsif ($viewer{server}) { + if (defined $viewer{msg}) { + @actString = ((uc setc()).": $viewer{msg}"); + } + else { + @actString = (); + } + } + elsif (defined $viewer{msg}) { + @actString = ((uc setc()).": $viewer{msg}"); + } + if (@actString) { + Irssi::timeout_add_once(100, 'syncLines', undef); + } + elsif ($currentLines) { + killOldStatus(); + $currentLines = 0; + } +} + +sub reset_awl { + Irssi::timeout_remove($shade_line_timer) if $shade_line_timer; $shade_line_timer = undef; + my $was_sort = $S{sort} // ''; + my $was_xform = $S{xform} // ''; + my $was_shared = $S{shared_sbar}; + my $was_no_hint = $S{no_mode_hint}; + my $was_custom_key = $S{custom_key_re} // ''; + %S = ( + sort => Irssi::settings_get_str( set 'sort'), + fancy_abbrev => Irssi::settings_get_str('fancy_abbrev'), + xform => Irssi::settings_get_str( set 'custom_xform'), + block => Irssi::settings_get_int( set 'block'), + banned_on => Irssi::settings_get_bool('banned_channels_on'), + prefer_name => Irssi::settings_get_bool(set 'prefer_name'), + hide_data => Irssi::settings_get_int( set 'hide_data'), + hide_name => Irssi::settings_get_int( set 'hide_name_data'), + hide_empty => Irssi::settings_get_int( set 'hide_empty'), + custom_key_re => Irssi::settings_get_str( set 'custom_key_re'), + detach => Irssi::settings_get_str( set 'detach'), + detach_data => Irssi::settings_get_int( set 'detach_data'), + detach_aht => Irssi::settings_get_bool(set 'detach_aht'), + sbar_maxlen => Irssi::settings_get_bool(set 'sbar_maxlength'), + placement => Irssi::settings_get_str( set 'placement'), + position => Irssi::settings_get_int( set 'position'), + maxlines => Irssi::settings_get_int( set 'maxlines'), + maxcolumns => Irssi::settings_get_int( set 'maxcolumns'), + all_disable => Irssi::settings_get_bool(set 'all_disable'), + height_adjust => Irssi::settings_get_int( set 'height_adjust'), + mouse_offset => Irssi::settings_get_int( set 'mouse_offset'), + mouse_scroll => Irssi::settings_get_int( 'mouse_scroll'), + mouse_escape => Irssi::settings_get_int( 'mouse_escape'), + line_shade => Irssi::settings_get_time(set 'last_line_shade'), + no_mode_hint => Irssi::settings_get_bool(set 'no_mode_hint'), + true_colour => Irssi::parse_special('$colors_ansi_24bit'), + viewer_launch => Irssi::settings_get_bool(set 'viewer_launch'), + viewer_launch_env => Irssi::settings_get_str(set 'viewer_launch_env'), + viewer_xwin_command => Irssi::settings_get_str(set 'viewer_xwin_command'), + viewer_custom_command => Irssi::settings_get_str(set 'viewer_custom_command'), + viewer_tmux_position => Irssi::settings_get_str(set 'viewer_tmux_position'), + ); + $S{fancy_strict} = $S{fancy_abbrev} =~ /^strict/i; + $S{fancy_head} = $S{fancy_abbrev} =~ /^head/i; + my $shared = Irssi::settings_get_str(set 'shared_sbar'); + if ($shared =~ /^(\d+)([<])(\d+)$/) { + $S{shared_sbar} = [$1, $2, $3]; + } + else { + Irssi::settings_set_str(set 'shared_sbar', 'OFF'); + $S{shared_sbar} = undef; + } + lock_keys(%S); + if ($was_sort ne $S{sort}) { + $print_text_activity = undef; + my @sort_order = grep { @$_ > 4 } map { + s/^\s*//; + my $reverse = s/^\W*\K[-!]//; + my $undef_check = s/^\W*\K~// ? 1 : undef; + my $equal_check = s/=(.*)\s?$// ? $1 : undef; + s/\s*$//; + my $ignore_case = s/#i$// ? 1 : undef; + + $print_text_activity = 1 if $_ eq 'last_line'; + + my @path = split '/'; + my $class_check = @path && $path[-1] =~ s/(::.*)$// ? $1 : undef; + my $lru = "@path" eq 'lru'; + + [ $reverse ? -1 : 1, $undef_check, $equal_check, $class_check, $ignore_case, $lru, @path ] + } "$S{sort}," =~ /([^+,]*|[^+,]*=[^,]*?\s(?=\+)|[^+,]*=[^,]*)[+,]/g; + $window_sort_func = sub { + no warnings qw(numeric uninitialized); + for my $so (@sort_order) { + my @x = map { + my $ret = 0; + $_ = lc1459($_) if defined $_ && !ref $_ && $so->[4]; + $ret = $_ eq ($so->[4] ? lc1459($so->[2]) : $so->[2]) ? 1 : -1 if defined $so->[2]; + $ret = defined $_ ? ($ret || -3) : 3 if $so->[1]; + $ret = ref $_ && $_->isa('Irssi'.$so->[3]) ? 2 : ($ret || -2) if $so->[3]; + -$ret || $_ + } + map { + $so->[5] ? $_->[0] : reduce { return unless ref $a; $a->{$b} } $_->[1], @{$so}[6..$#$so] + } $a, $b; + return ((($x[0] <=> $x[1] || $x[0] cmp $x[1]) * $so->[0]) || next); + } + return ($a->[1]{refnum} <=> $b->[1]{refnum}); + }; + } + if ($was_xform ne $S{xform}) { + if ($S{xform} !~ /\S/) { + $custom_xform = undef; + } + else { + my $script_pkg = __PACKAGE__ . '::custom_xform'; + local $@; + $custom_xform = eval qq{ +package $script_pkg; +use strict; +no warnings; +our (\$QUERY, \$CHANNEL, \$TAG, \$NAME); +return sub { +# line 1 @{[ set 'custom_xform' ]}\n$S{xform}\n}}; + if ($@) { + $@ =~ /^(.*)/; + print '%_'.(set 'custom_xform').'%_ did not compile: '.$1; + } + } + } + if ($was_custom_key ne $S{custom_key_re}) { + my $custom_key = $S{custom_key_re}; + my $was_custom_key_re = $custom_key_re; + local $@; + eval { $custom_key_re = qr/(?i)$custom_key/; 1 } + or do { + print '%_'.(set 'custom_key_re').'%_ did not compile: ' + . do { $@ =~ /(.*) at / && $1 }; + $custom_key_re = qr/(?!)/; + }; + if ($was_custom_key_re ne $custom_key_re) { + update_keymap(); + } + } + + my $new_settings = join "\n", $VIEWER_MODE + ? ("\\", $S{block}, $S{height_adjust}, $S{maxlines}, $S{maxcolumns}, $S{true_colour}) + : ("!", $S{placement}, $S{position}); + + my $first_viewer = $settings_str eq '1'; + if ($settings_str ne $new_settings) { + @actString = (); + %abbrev_cache = (); + $currentLines = 0; + killOldStatus(); + delete $viewer{client_settings}; + $settings_str = $new_settings; + } + + my $was_mouse_mode = $MOUSE_ON; + if ($MOUSE_ON = Irssi::settings_get_bool(set 'mouse') and !$was_mouse_mode) { + install_mouse(); + } + elsif ($was_mouse_mode and !$MOUSE_ON) { + uninstall_mouse(); + } + + unless ($first_viewer) { + my $path = Irssi::settings_get_str(set 'path'); + my $was_viewer_mode = $VIEWER_MODE; + if ($was_viewer_mode && + defined $viewer{path} && $viewer{path} ne $path) { + stop_viewer(); + $was_viewer_mode = 0; + } + elsif ($was_viewer_mode && $S{no_mode_hint} != $was_no_hint + 0) { + set_viewer_mode_hint(); + } + $viewer{path} = $path; + if ($VIEWER_MODE = Irssi::settings_get_bool(set 'viewer') and !$was_viewer_mode) { + start_viewer(); + } + elsif ($was_viewer_mode and !$VIEWER_MODE) { + stop_viewer(); + } + } + + %banned_channels = map { lc1459(as_uni($_)) => undef } + split ' ', Irssi::settings_get_str('banned_channels'); + + %detach_map = ($S{detach_aht} + ? (map { ( lc1459(as_uni($_)) => undef ) } + split ' ', Irssi::settings_get_str('activity_hide_targets')) : (), + (map { my ($k, $v) = (split /(?:,(-?\d+))$/, $_)[0, 1]; + ( lc1459(as_uni($k)) => $v ) } + split ' ', $S{detach})); + + my @sb_base = split /\177/, sb_format_expand("{sbstart}{sb \177}{sbend}"), 2; + $sb_base_width_pre = sb_length($sb_base[0]); + $sb_base_width_post = max 0, sb_length($sb_base[1])-1; + $sb_base_width = $sb_base_width_pre + $sb_base_width_post; + + if ($print_text_activity && $S{line_shade}) { + $shade_line_timer = Irssi::timeout_add(max(10 * GLOB_QUEUE_TIMER, 100*$S{line_shade}**(1/3)), 'wl_changed', undef); + } + + $CHANGED{AWINS} = 1; +} + +sub hide_window { + my ($data) = @_; + my $ent; + + $data =~ s/\s*$//; + my $win = Irssi::active_win; + my $number = $win->{refnum}; + my $name = as_uni($win->{name}); + my $active = as_uni($win->get_active_name) // ''; + my $tag = $win->{active} && $win->{active}{server} ? as_uni($win->{active}{server}{tag}) // '' : ''; + if (length $name) { + $ent = "$name"; + } + elsif (length $tag && length $active) { + $ent = "$tag/$active"; + } + else { + $ent = "$number"; + } + + my $found = 0; + my @setting; + for my $s (split ' ', $S{detach}) { + my ($k, $v) = (split /(?:,(-?\d+))$/, $s)[0, 1]; + if (lc1459(as_uni($k)) eq lc1459($ent)) { + unless ($found) { + if ($data =~ /^(-?\d+)$/) { + $ent .= ",$1"; + } + if (defined $v && 0 == abs $v) { + $win->print("Hiding window $ent"); + } + push @setting, as_tc($ent); + $found = 1; + } + } + else { + push @setting, defined $v ? "$k,$v" : $k; + } + } + unless ($found) { + $win->print("Hiding window $ent"); + if ($data =~ /^(-?\d+)$/) { + $ent .= ",$1"; + } + push @setting, as_tc($ent); + } + + if (@setting) { + Irssi::command("^set ".(set 'detach')." @setting"); + } else { + Irssi::command("^set -clear ".(set 'detach')); + } +} + +sub unhide_window { + my ($data, $server, $witem) = @_; + my $win = Irssi::active_win; + my $number = $win->{refnum}; + my $name = as_uni($win->{name}); + my $active = as_uni($win->get_active_name) // ''; + my $tag = $win->{active} && $win->{active}{server} ? as_uni($win->{active}{server}{tag}) // '' : ''; + + my %detach_aht; + if ($S{detach_aht}) { + %detach_aht = (map { ( lc1459(as_uni($_)) => undef ) } + split ' ', Irssi::settings_get_str('activity_hide_targets')); + } + my @setting; + my @kills = (length $name ? $name : undef, + length $tag && length $active ? "$tag/$active" : undef, + length $active ? $active : undef, + $number); + my @was_unhidden = (0) x @kills; + for my $s (split ' ', $S{detach}) { + my ($k, $v) = (split /(?:,(-?\d+))$/, $s)[0, 1]; + my $k2 = lc1459(as_uni($k)); + my $kill; + for my $ki (0..$#kills) { + if (defined $kills[$ki] && $k2 eq lc1459($kills[$ki])) { + $kill = $ki; + } + } + + if (defined $kill) { + if (defined $v && 0 == abs $v) { + $was_unhidden[$kill] = 1; + push @setting, defined $v ? "$k,$v" : $k; + } else { + $win->print("Unhiding window $kills[$kill]"); + } + } + else { + push @setting, defined $v ? "$k,$v" : $k; + } + } + my @is_hidden = (defined $kills[0] && (exists $detach_map{"*"} || exists $detach_map{"::all"}), + defined $kills[1] && (exists $detach_map{lc1459("$tag/*")} || exists $detach_map{lc1459("$tag/::all")} + || exists $detach_map{"*"} || exists $detach_map{"::all"}), + defined $kills[2] && (exists $detach_map{"*"} || exists $detach_map{"::all"}), + (exists $detach_map{"*"} || exists $detach_map{"::all"}) + ); + for my $ki (1, 2, 0, 3) { + if ($is_hidden[$ki]) { + unless ($was_unhidden[$ki]) { + $win->print("Unhiding window $kills[$ki]"); + push @setting, "$kills[$ki],0"; + $was_unhidden[$ki] = 1; + } + last; + } + } + my @is_hidden_aht = (defined $kills[0] && (exists $detach_aht{lc1459($name)} + || exists $detach_aht{"*"} || exists $detach_aht{"::all"}), + defined $kills[1] && (exists $detach_aht{lc1459("$tag/$active")} + || exists $detach_aht{lc1459($active)} + || exists $detach_aht{lc1459("$tag/*")} || exists $detach_aht{lc1459("$tag/::all")} + || exists $detach_aht{"*"} || exists $detach_aht{"::all"}), + defined $kills[2] && (exists $detach_aht{lc1459($active)} + || exists $detach_aht{"*"} || exists $detach_aht{"::all"}), + (exists $detach_aht{$number} || exists $detach_aht{"*"} || exists $detach_aht{"::all"}) + ); + for my $ki (1, 2, 0, 3) { + if ($is_hidden_aht[$ki]) { + unless ($was_unhidden[$ki]) { + $win->print("Unhiding window $kills[$ki], it is hidden because ".(set 'detach_aht')." is ON"); + push @setting, "$kills[$ki],0"; + $was_unhidden[$ki] = 1; + } + last; + } + } + + if (@setting) { + Irssi::command("^set ".(set 'detach')." @setting"); + } else { + Irssi::command("^set -clear ".(set 'detach')); + } +} + +sub ack_window { + my ($data, $server, $witem) = @_; + my $win = Irssi::active_win; + my $number = $win->{refnum}; + if (grep { $_->{cmd} eq 'ack' } Irssi::commands) { + my $Orig_Irssi_windows = \&Irssi::windows; + local *Irssi::windows = sub () { grep { !_is_detached($_, $number) } $Orig_Irssi_windows->() }; + Irssi::command("ack" . (length $data ? " $data" : "")); + } else { + my $ignore_refnum = Irssi::settings_get_bool('active_window_ignore_refnum'); + my $max_win; + my $max_act = 0; + my $max_ref = 0; + for my $rec (Irssi::windows) { + next if _is_detached($rec, $number); + + # ignore refnum + if ($ignore_refnum && + $rec->{data_level} > 0 && $max_act < $rec->{data_level}) { + $max_act = $rec->{data_level}; + $max_win = $rec; + } + + # windows with lower refnums break ties + elsif (!$ignore_refnum && + $rec->{data_level} > 0 && + ($rec->{data_level} > $max_act || + ($rec->{data_level} == $max_act && $rec->{refnum} < $max_ref))) { + $max_act = $rec->{data_level}; + $max_win = $rec; + $max_ref = $rec->{refnum}; + } + } + $max_win->set_active if defined $max_win; + } +} + +sub refnum_changed { + my ($win, $old_refnum) = @_; + my @old_setting = split ' ', $S{detach}; + my @setting = map { + my ($k, $v) = (split /(?:,(-?\d+))$/, $_)[0, 1]; + if ($k eq $old_refnum) { + $win->{refnum} . (defined $v ? ",$v" : "") + } + else { + $_ + } + } @old_setting; + if ("@old_setting" ne "@setting") { + $S{detach} = "@setting"; + Irssi::settings_set_str(set 'detach', "@setting"); + &setup_changed; + } + else { + &wl_changed; + } +} + +sub window_destroyed { + my ($win) = @_; + my @old_setting = split ' ', $S{detach}; + my @setting = grep { + my ($k, $v) = (split /(?:,(-?\d+))$/, $_)[0, 1]; + if ($k eq $win->{refnum}) { + 0; + } + else { + 1; + } + } @old_setting; + if ("@old_setting" ne "@setting") { + $S{detach} = "@setting"; + Irssi::settings_set_str(set 'detach', "@setting"); + &setup_changed; + } + else { + &awins_changed; + } +} + +sub stop_mouse_tracking { + print STDERR "\e[?1005l\e[?1000l"; +} +sub start_mouse_tracking { + print STDERR "\e[?1000h\e[?1005h"; +} +sub install_mouse { + Irssi::command_bind('mouse_xterm' => 'mouse_xterm'); + Irssi::command('^bind meta-[M command mouse_xterm'); + Irssi::signal_add_first('gui key pressed' => 'mouse_key_hook'); + start_mouse_tracking(); +} +sub uninstall_mouse { + stop_mouse_tracking(); + Irssi::signal_remove('gui key pressed' => 'mouse_key_hook'); + Irssi::command('^bind -delete meta-[M'); + Irssi::command_unbind('mouse_xterm' => 'mouse_xterm'); +} + +sub awl_mouse_event { + return if $VIEWER_MODE; + if ((($_[0] == 3 and $_[3] == 0) + || $_[0] == 64 || $_[0] == 65) and + $_[1] == $_[4] and $_[2] == $_[5]) { + my $top = lc $S{placement} eq 'top'; + my ($pos, $line) = @_[1 .. 2]; + unless ($top) { + $line -= $screenHeight; + $line += $currentLines; + $line += $S{mouse_offset}; + } + else { + $line -= $S{mouse_offset}; + } + $pos -= $sb_base_width_pre; + return if $line < 0 || $line >= $currentLines; + if ($_[0] == 64) { + Irssi::command('window up'); + } + elsif ($_[0] == 65) { + Irssi::command('window down'); + } + elsif (exists $mouse_coords{$line}{$pos}) { + my $win = $mouse_coords{$line}{$pos}; + Irssi::command('window ' . $win); + } + Irssi::signal_stop; + } +} + +sub mouse_scroll_event { + return unless $S{mouse_scroll}; + if (($_[3] == 64 or $_[3] == 65) and + $_[0] == $_[3] and $_[1] == $_[4] and $_[2] == $_[5]) { + my $cmd = 'scrollback goto ' . ($_[3] == 64 ? '-' : '+') . $S{mouse_scroll}; + Irssi::active_win->command($cmd); + Irssi::signal_stop; + } + elsif ($_[0] == 64 or $_[0] == 65) { + Irssi::signal_stop; + } +} + +sub mouse_escape { + return unless $S{mouse_escape} > 0; + if ($_[0] == 3) { + my $tm = $S{mouse_escape}; + $tm *= 1000 if $tm < 1000; + stop_mouse_tracking(); + Irssi::timeout_add_once($tm, 'start_mouse_tracking', undef); + Irssi::signal_stop; + } +} + +sub UNLOAD { + @actString = (); + killOldStatus(); + stop_viewer() if $VIEWER_MODE; + uninstall_mouse() if $MOUSE_ON; +} + +sub addPrintTextHook { # update on print text + return unless defined $^S; + return if $BLOCK_ALL; + return unless $print_text_activity; + return if $_[0]->{level} == MSGLEVEL_CLIENTNOTICE and $_[0]->{target} eq '' + and !defined($_[0]->{server}); + &wl_changed; +} + +sub block_event_window_change { + Irssi::signal_stop; +} + +sub update_awins { + my @wins = Irssi::windows; + local $BLOCK_ALL = 1; + Irssi::signal_add_first('window changed' => 'block_event_window_change'); + my $bwin = + my $awin = Irssi::active_win; + my $lwin; + my $defer_irssi_broken_last; + unless ($wins[0]{refnum} == $awin->{refnum}) { + # special case: more than 1 last win, so /win last; + # /win last doesn't come back to the current window. eg. after + # connect & autojoin; we can't handle this situation, bail out + $defer_irssi_broken_last = 1; + } + else { + $awin->command('window last'); + $lwin = Irssi::active_win; + $lwin->command('window last'); + $defer_irssi_broken_last = $lwin->{refnum} == $bwin->{refnum}; + } + my $awin_counter = 0; + Irssi::signal_remove('window changed' => 'block_event_window_change'); + unless ($defer_irssi_broken_last) { + # we need to keep the fe-windows code running here + Irssi::signal_add_priority('window changed' => 'block_event_window_change', -99); + %awins = %wnmap_exp = (); + do { + Irssi::active_win->command('window up'); + $awin = Irssi::active_win; + $awins{$awin->{refnum}} = undef; + ++$awin_counter; + } until ($awin->{refnum} == $bwin->{refnum} || $awin_counter >= @wins); + Irssi::signal_remove('window changed' => 'block_event_window_change'); + + Irssi::signal_add_first('window changed' => 'block_event_window_change'); + for my $key (keys %wnmap) { + next unless Irssi::window_find_name($key) || Irssi::window_find_item($key); + $awin->command("window goto $key"); + my $cwin = Irssi::active_win; + $wnmap_exp{ $cwin->{refnum} } = $wnmap{$key}; + $cwin->command('window last') + if $cwin->{refnum} != $awin->{refnum}; + } + for my $win (reverse @wins) { # restore original window order + Irssi::active_win->command('window '.$win->{refnum}); + } + $awin->command('window '.$lwin->{refnum}); # restore last win + Irssi::active_win->command('window last'); + Irssi::signal_remove('window changed' => 'block_event_window_change'); + } + $CHANGED{WL} = 1; +} + +sub resizeTerm { + if (defined (my $r = `stty size 2>/dev/null`)) { + ($screenHeight, $screenWidth) = split ' ', $r; + $CHANGED{SETUP} = 1; + } + else { + $CHANGED{SIZE} = 1; + } +} + +sub awl_refresh { + $globTime = undef; + resizeTerm() if delete $CHANGED{SIZE}; + reset_awl() if delete $CHANGED{SETUP}; + update_awins() if delete $CHANGED{AWINS}; + update_wl() if delete $CHANGED{WL}; +} + +sub termsize_changed { $CHANGED{SIZE} = 1; &queue_refresh; } +sub setup_changed { $CHANGED{SETUP} = 1; &queue_refresh; } +sub awins_changed { $CHANGED{AWINS} = 1; &queue_refresh; } +sub wl_changed { $CHANGED{WL} = 1; &queue_refresh; } + +sub window_changed { + &awins_changed if $_[1]; +} + +sub queue_refresh { + return if $BLOCK_ALL; + Irssi::timeout_remove($globTime) + if defined $globTime; # delay the update further + $globTime = Irssi::timeout_add_once(GLOB_QUEUE_TIMER, 'awl_refresh', undef); +} + +sub awl_init { + termsize_changed(); + setup_changed(); + update_keymap(); + Irssi::timeout_remove($globTime) + if defined $globTime; + awl_refresh(); + termsize_changed(); +} + +sub runsub { + my $cmd = shift; + sub { + my ($data, $server, $item) = @_; + Irssi::command_runsub($cmd, $data, $server, $item); + }; +} + +Irssi::signal_register({ + 'gui mouse' => [qw/int int int int int int/], + }); +{ my $broken_expandos = (Irssi::version >= 20081128 && Irssi::version < 20110210) + ? sub { my $x = shift; $x =~ s/\$\{cumode_space\}/ /; $x } : undef; + Irssi::theme_register([ + map { $broken_expandos ? $broken_expandos->($_) : $_ } + set 'display_nokey' => '$N${cumode_space}$H$C$S', + set 'display_key' => '$Q${cumode_space}$H$C$S', + set 'display_nokey_visible' => '%2$N${cumode_space}$H$C$S', + set 'display_key_visible' => '%2$Q${cumode_space}$H$C$S', + set 'display_nokey_active' => '%1$N${cumode_space}$H$C$S', + set 'display_key_active' => '%1$Q${cumode_space}$H$C$S', + set 'display_header' => '%8$C|${N}', + set 'name_display' => '$0', + set 'separator' => ' ', + set 'separator2' => '', + set 'abbrev_chars' => "~\x{301c}", + set 'viewer_item_bg' => sb_format_expand('{sb_background}'), + set 'title' => '\V'.setc().'\:', + ]); +} +Irssi::settings_add_bool(setc, set 'prefer_name', 0); # +Irssi::settings_add_int( setc, set 'hide_empty', 0); # +Irssi::settings_add_int( setc, set 'hide_data', 0); # +Irssi::settings_add_str( setc, set 'detach', ''); # +Irssi::settings_add_int( setc, set 'detach_data', -3); # +Irssi::settings_add_bool(setc, set 'detach_aht', 0); # +Irssi::settings_add_int( setc, set 'hide_name_data', 0); # +Irssi::settings_add_int( setc, set 'maxlines', 9); # +Irssi::settings_add_int( setc, set 'maxcolumns', 4); # +Irssi::settings_add_int( setc, set 'block', 15); # +Irssi::settings_add_bool(setc, set 'sbar_maxlength', 1); # +Irssi::settings_add_int( setc, set 'height_adjust', 2); # +Irssi::settings_add_str( setc, set 'sort', 'refnum'); # +Irssi::settings_add_str( setc, set 'placement', 'bottom'); # +Irssi::settings_add_int( setc, set 'position', 0); # +Irssi::settings_add_bool(setc, set 'all_disable', 1); # +Irssi::settings_add_bool(setc, set 'viewer', 1); # +Irssi::settings_add_str( setc, set 'shared_sbar', 'OFF'); # +Irssi::settings_add_bool(setc, set 'mouse', 0); # +Irssi::settings_add_str( setc, set 'path', Irssi::get_irssi_dir . '/_windowlist'); # +Irssi::settings_add_str( setc, set 'custom_xform', ''); # +Irssi::settings_add_str( setc, set 'custom_key_re', 'f\d+'); # +Irssi::settings_add_time(setc, set 'last_line_shade', '0'); # +Irssi::settings_add_int( setc, set 'mouse_offset', 1); # +Irssi::settings_add_int( setc, 'mouse_scroll', 3); # +Irssi::settings_add_int( setc, 'mouse_escape', 1); # +Irssi::settings_add_str( setc, 'banned_channels', ''); +Irssi::settings_add_bool(setc, 'banned_channels_on', 1); +Irssi::settings_add_str( setc, 'fancy_abbrev', 'fancy'); # +Irssi::settings_add_bool(setc, set 'no_mode_hint', 0); # +Irssi::settings_add_bool(setc, set 'viewer_launch', 1); # +Irssi::settings_add_str( setc, set 'viewer_launch_env', ''); # +Irssi::settings_add_str( setc, set 'viewer_tmux_position', 'left'); # +Irssi::settings_add_str( setc, set 'viewer_xwin_command', 'xterm +sb -e %A'); # +Irssi::settings_add_str( setc, set 'viewer_custom_command', ''); # + +Irssi::signal_add_last({ + 'setup changed' => 'setup_changed', + 'print text' => 'addPrintTextHook', + 'terminal resized' => 'termsize_changed', + 'setup reread' => 'screenFullRedraw', + 'window hilight' => 'wl_changed', + 'command format' => 'wl_changed', +}); +Irssi::signal_add({ + 'window changed' => 'window_changed', + 'window item changed' => 'wl_changed', + 'window changed automatic' => 'window_changed', + 'window created' => 'awins_changed', + 'window destroyed' => 'window_destroyed', + 'window name changed' => 'wl_changed', + 'window refnum changed' => 'refnum_changed', +}); +Irssi::signal_add_last('gui mouse' => 'mouse_escape'); +Irssi::signal_add_last('gui mouse' => 'mouse_scroll_event'); +Irssi::signal_add_last('gui mouse' => 'awl_mouse_event'); +Irssi::command_bind( setc() => runsub(setc()) ); +Irssi::command_bind( setc() . ' redraw' => 'screenFullRedraw' ); +Irssi::command_bind( setc() . ' restart' => 'restartViewerServer' ); +Irssi::command_bind( setc() . ' attach' => 'unhide_window' ); +Irssi::command_bind( setc() . ' detach' => 'hide_window' ); +Irssi::command_bind( setc() . ' ack' => 'ack_window' ); + +{ + my $l = set 'shared'; + { + no strict 'refs'; + *{$l} = $awl_shared_empty; + } + Irssi::statusbar_item_register($l, '$0', $l); +} + +awl_init(); + +# Mouse script based on irssi mouse patch by mirage +{ my $mouse_status = -1; # -1:off 0,1,2:filling mouse_combo + my @mouse_combo = (-1, -1, -1); # 0:button 1:x 2:y + my @mouse_previous = (-1, -1, -1); # previous contents of mouse_combo + + sub mouse_xterm_off { + $mouse_status = -1; + } + sub mouse_xterm { + $mouse_status = 0; + Irssi::timeout_add_once(10, 'mouse_xterm_off', undef); + } + + sub mouse_key_hook { + my ($key) = @_; + if ($mouse_status != -1) { + if ($mouse_status == 0) { + @mouse_previous = @mouse_combo; + #if @mouse_combo && $mouse_combo[0] < 64; + } + $mouse_combo[$mouse_status] = $key - 32; + $mouse_status++; + if ($mouse_status == 3) { + $mouse_status = -1; + # match screen coordinates + $mouse_combo[1]--; + $mouse_combo[2]--; + Irssi::signal_emit('gui mouse', @mouse_combo[0 .. 2], @mouse_previous[0 .. 2]); + } + Irssi::signal_stop; + } + } +} + +sub string_LCSS { + my $str = join "\0", @_; + (sort { length $b <=> length $a } $str =~ /(?=(.+).*\0.*\1)/g)[0] +} + +# workaround for issue #271 +{ package Irssi::Nick } + +# workaround for issue #572 +@Irssi::UI::Exec::ISA = 'Irssi::Windowitem' + if Irssi::version >= 20140822 && Irssi::version <= 20161101 && !@Irssi::UI::Exec::ISA; + +UNITCHECK +{ package AwlViewer; + use strict; + use warnings; + no warnings 'redefine'; + use Encode; + use IO::Socket::UNIX; + use IO::Select; + use List::Util qw(max); + use constant BLOCK_SIZE => 1024; + use constant RECONNECT_TIME => 5; + + my $sockpath; + + our $VERSION = '0.8'; + + our ($got_int, $resized, $timeout); + + my %vars; + my (%c2w, @seqlist); + my %mouse_coords; + my (@mouse, @last_mouse); + my ($err, $sock, $loop); + my ($keybuf, $rcvbuf); + my @screen; + my ($screenHeight, $screenWidth); + my ($disp_update, $fs_open, $one_shot_integration, $one_shot_resize); + my $integration_position; + my $show_title_bar; + + sub connect_it { + $sock = IO::Socket::UNIX->new( + Type => SOCK_STREAM, + Peer => $sockpath, + ); + unless ($sock) { + $err = $!; + return; + } + $sock->blocking(0); + $loop->add($sock); + } + + sub remove_conn { + my $fh = shift; + $loop->remove($fh); + $fh->close; + $sock = undef; + %vars = (); + @screen = (); + } + + { package Terminfo; # xterm + sub civis { "\e[?25l" } + sub sc { "\e7" } + sub cup { "\e[" . ($_[0] + 1) . ';' . ($_[1] + 1) . 'H' } + sub el { "\e[K" } + sub rc { "\e8" } + sub cnorm { "\e[?25h" } + sub setab { "\e[4" . $_[0] . 'm' } + sub setaf { "\e[3" . $_[0] . 'm' } + sub setaf16 { "\e[9" . $_[0] . 'm' } + sub setab16 { "\e[10" . $_[0] . 'm' } + sub setaf256 { "\e[38;5;" . $_[0] . 'm' } + sub setab256 { "\e[48;5;" . $_[0] . 'm' } + sub setafrgb { "\e[38;2;" . $_[0] . ';' . $_[1] . ';' . $_[2] . 'm' } + sub setabrgb { "\e[48;2;" . $_[0] . ';' . $_[1] . ';' . $_[2] . 'm' } + sub sgr0 { "\e[0m" } + sub bold { "\e[1m" } + sub it { "\e[3m" } + sub ul { "\e[4m" } + sub blink { "\e[5m" } + sub rev { "\e[7m" } + sub op { "\e[39;49m" } + sub exit_bold { "\e[22m" } + sub exit_it { "\e[23m" } + sub exit_ul { "\e[24m" } + sub exit_blink { "\e[25m" } + sub exit_rev { "\e[27m" } + sub smcup { "\e[?1049h" } + sub rmcup { "\e[?1049l" } + sub smmouse { "\e[?1000h\e[?1005h" } + sub rmmouse { "\e[?1005l\e[?1000l" } + } + + sub init { + $sockpath = shift // "$ENV{HOME}/.irssi/_windowlist"; + STDOUT->autoflush(1); + printf "\r%swaiting for %s...", Terminfo::sc, $::IRSSI{name}; + + `stty -icanon -echo`; + + $loop = IO::Select->new; + STDIN->blocking(0); + $loop->add(\*STDIN); + + $SIG{INT} = sub { + $got_int = 1 + }; + $SIG{WINCH} = sub { + $resized = 1 + }; + + $resized = 3; + + $disp_update = 2; + + $show_title_bar = 1; + } + + sub enter_fs { + return if $fs_open; + safe_print(Terminfo::rc, Terminfo::smcup, Terminfo::civis, Terminfo::smmouse); + $fs_open = 1; + } + + sub leave_fs { + return unless $fs_open; + safe_print(Terminfo::rmmouse, Terminfo::cnorm, Terminfo::rmcup); + safe_print(sprintf "\r%swaiting for %s...", Terminfo::sc, $::IRSSI{name}) if $_[0]; + + $fs_open = 0; + } + + sub end_prog { + leave_fs(); + STDIN->blocking(1); + `stty sane`; + printf "\r%s%sthanks for using %s\n", Terminfo::rc, Terminfo::el, $::IRSSI{name}; + } + + sub safe_print { + my $st = STDIN->blocking(1); + print @_; + STDIN->blocking($st); + } + + sub safe_qx { + my $st = STDIN->blocking(1); + my $ret = `$_[0]`; + STDIN->blocking($st); + $ret + } + + sub safe_print_sock { + return unless $sock; + my $was = $sock->blocking(1); + $sock->print(@_); + $sock->blocking($was); + } + + sub process_recv { + my $need = 0; + while ($rcvbuf =~ s/\n(.+)_BEGIN\n((?: .*\n)*)\1_END\n//) { + my $var = lc $1; + my $data = $2; + my @data = split "\n ", "\n$data ", -1; + shift @data; pop @data; + my $itembg = $vars{itembg}; + if ($var =~ s/list$//) { + $vars{$var} = \@data; + } + elsif ($var =~ s/map$//) { + $vars{$var} = +{ @data }; + } + else { + $vars{$var} = join "\n", @data; + } + $need = 1 if $var eq 'win'; + $need = 1 if $var eq 'redraw' && $vars{$var}; + if (($itembg//'') ne ($vars{itembg}//'')) { + $need = $vars{redraw} = 1; + } + _build_keymap() if $var eq 'key2'; + } + $need + } + + { my %ansi_table; + my ($i, $j, $k) = (0, 0, 0); + my %term_state; + sub reset_term_state { my %old_term = %term_state; %term_state = (); %old_term } + sub set_term_state { my %old_term = %term_state; %term_state = @_; %old_term } + %ansi_table = ( + # fe-common::core::formats.c:format_expand_styles + (map { my $t = $i++; ($_ => sub { my $n = $term_state{hicolor} ? \&Terminfo::setab16 : \&Terminfo::setab; + $n->($t) }) } (split //, '01234567' )), + (map { my $t = $j++; ($_ => sub { my $n = $term_state{hicolor} ? \&Terminfo::setaf16 : \&Terminfo::setaf; + $n->($t) }) } (split //, 'krgybmcw' )), + (map { my $t = $k++; ($_ => sub { my $n = $term_state{hicolor} ? \&Terminfo::setaf : \&Terminfo::setaf16; + $n->($t) }) } (split //, 'KRGYBMCW')), + # reset + n => sub { $term_state{hicolor} = 0; my $r = Terminfo::op; + for (qw(blink rev bold)) { + $r .= Terminfo->can("exit_$_")->() if delete $term_state{$_}; + } + { + local $ansi_table{n} = $ansi_table{N}; + $r .= formats_to_ansi_basic($vars{itembg}); + } + $r + }, + N => sub { reset_term_state(); Terminfo::sgr0 }, + # flash/bright + F => sub { my $n = 'blink'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() }, + # reverse + 8 => sub { my $n = 'rev'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() }, + # bold + "_" => sub { my $n = 'bold'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() }, + # underline + U => sub { my $n = 'ul'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() }, + # italic + I => sub { my $n = 'it'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() }, + # bold, used as colour modifier if AWL_HI9 is set + 9 => $ENV{AWL_HI9} ? sub { $term_state{hicolor} ^= 1; '' } + : sub { my $n = 'bold'; my $e = ($term_state{$n} ^= 1) ? $n : "exit_$n"; Terminfo->can($e)->() }, + # delete other stuff + (map { $_ => sub { '' } } (split //, ':|>#[')), + # escape + (map { my $close = $_; $_ => sub { $close } } (split //, '{}%')), + ); + for my $base (0 .. 15) { + my $close = $base; + my $idx = ($close&8) | ($close&4)>>2 | ($close&2) | ($close&1)<<2; + $ansi_table{ (sprintf "x0%x", $close) } = + $ansi_table{ (sprintf "x0%X", $close) } = + sub { Terminfo::setab256($idx) }; + $ansi_table{ (sprintf "X0%x", $close) } = + $ansi_table{ (sprintf "X0%X", $close) } = + sub { Terminfo::setaf256($idx) }; + } + for my $plane (1 .. 6) { + for my $coord (0 .. 35) { + my $close = 16 + ($plane-1) * 36 + $coord; + my $ch = $coord < 10 ? $coord : chr( $coord - 10 + ord 'a' ); + $ansi_table{ "x$plane$ch" } = + $ansi_table{ "x$plane\U$ch" } = + sub { Terminfo::setab256($close) }; + $ansi_table{ "X$plane$ch" } = + $ansi_table{ "X$plane\U$ch" } = + sub { Terminfo::setaf256($close) }; + } + } + for my $gray (0 .. 23) { + my $close = 232 + $gray; + my $ch = chr( $gray + ord 'a' ); + $ansi_table{ "x7$ch" } = + $ansi_table{ "x7\U$ch" } = + sub { Terminfo::setab256($close) }; + $ansi_table{ "X7$ch" } = + $ansi_table{ "X7\U$ch" } = + sub { Terminfo::setaf256($close) }; + } + # fe-windows.c:color_24bit_256 + my $cc = sub { + use integer; + + my $cstep_size = 40; + my $cstep_start = 0x5f; + + my $gstep_size = 10; + my $gstep_start = 0x08; + + my @dist = (0) x 3; + my @r; my @gr; + + for (my $i = 0; $i < 3; ++$i) { + my $n = $_[$i]; + $gr[$i] = -1; + if ($n < $cstep_start /2) { + $r[$i] = 0; + $dist[$i] = -$cstep_size/2; + } + else { + $r[$i] = 1+(($n-$cstep_start + $cstep_size /2)/$cstep_size); + $dist[$i] = (($n-$cstep_start + $cstep_size /2)% $cstep_size - $cstep_size/2); + } + if ($n < $gstep_start /2) { + $gr[$i] = -1; + } + else { + $gr[$i] = (($n-$gstep_start + $gstep_size /2)/$gstep_size); + } + } + if ($r[0] == $r[1] && $r[1] == $r[2] && + 4*abs($dist[0]) < $gstep_size && 4*abs($dist[1]) < $gstep_size && 4*abs($dist[2]) < $gstep_size) { + # skip gray detection + } + else { + my $j = $r[1] == $r[2] ? 0 : 1; + if (($r[0] == $r[1] || $r[$j] == $r[2]) && abs($r[$j]-$r[($j+1)% 3]) <= 1) { + my $k = $gr[1] == $gr[2] ? 0 : 1; + if (($gr[0] == $gr[1] || $gr[$k] == $gr[2]) && abs($gr[$k]-$gr[($k+1)% 3]) <= 2) { + if ($gr[$k] < 0) { + $r[0] = $r[1] = $r[2] = 0; + } + elsif ($gr[$k] > 23) { + $r[0] = $r[1] = $r[2] = 5; + } + else { + $r[0] = 6; + $r[1] = ($gr[$k] / 6); + $r[2] = $gr[$k]% 6; + } + } + } + } + return 16 + $r[0]*36 + $r[1] * 6 + $r[2]; + }; + $ansi_table{z} = sub { + my ($r, $g, $b) = map { hex } unpack '(A2)*', $_[0]; + $vars{tc} eq 'ON' ? Terminfo::setabrgb($r, $g, $b) : Terminfo::setab256($cc->($r, $g, $b)); + }; + $ansi_table{Z} = sub { + my ($r, $g, $b) = map { hex } unpack '(A2)*', $_[0]; + $vars{tc} eq 'ON' ? Terminfo::setafrgb($r, $g, $b) : Terminfo::setaf256($cc->($r, $g, $b)); + }; + sub formats_to_ansi_basic { + my $o = shift; + $o =~ s{(%((Z|z)(......)|X..|x..|.))}{ + if ($ansi_table{$2}) { $ansi_table{$2}->() } + elsif ($ansi_table{$3}) { $ansi_table{$3}->($4) } + else { $1 } + }gex; + $o + } + } + + sub _header { + my $str = $vars{title} // uc ::setc(); + my $ccs = qr/%(?:Z(?:[0-9A-F]{6})|X(?:[1-6][0-9A-Z]|7[A-X])|[0-9BCFGIKMNRUWY_])/i; + (my $stripstr = $str) =~ s/($ccs)//g; + my $space = int( ((abs $vars{block}) - length $stripstr) / (1 + length $stripstr)); + if ($space > 0) { + my $ss = ' ' x $space; + my @x = $str =~ /((?:$ccs)*\X(?:(?:$ccs)*$)?)/g; + $str = join $ss, '', @x, ''; + } + ($stripstr = $str) =~ s/($ccs)//g; + my $pad = max 0, (abs $vars{block}) - length $stripstr; + $str = ' ' x ($pad/2) . $str . ' ' x ($pad/2 + $pad%2); + $str + } + + sub _add_item { + my ($i, $j, $c, $wi, $screen, $mouse) = @_; + $screen->[$i][$j] = "%N%n$wi"; + if (exists $vars{mouse}{$c - 1}) { + $mouse->[$i][$j] = $vars{mouse}{$c - 1}; + } + } + sub update_screen { + $disp_update = 0; + unless ($sock && exists $vars{seplen} && exists $vars{block}) { + leave_fs(1); + return; + } + enter_fs(); + @screen = () if delete $vars{redraw}; + %mouse_coords = (); + my $ncols = ($vars{seplen} + abs $vars{block}) ? + int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ) : 0; + my $xenl = ($vars{seplen} + abs $vars{block}) + && $ncols > int( ($screenWidth + $vars{seplen} - 1) / ($vars{seplen} + abs $vars{block}) ); + my $nrows = $screenHeight - $vars{ha}; + my @wi = @{$vars{win}//[]}; + my $max_items = $ncols * $nrows; + my $c = $show_title_bar ? 1 : 0; + my $items = @wi + $c; + my $titems = $items > $max_items ? $max_items : $items; + my $i = 0; + my $j = 0; + my @new_screen; + my @new_mouse; + $new_screen[0][0] = _header() #. ' ' x $vars{seplen} + if $show_title_bar; + unless ($nrows > $ncols) { # line layout + ++$j if $show_title_bar; + for my $wi (@wi) { + if ($j >= $ncols) { + $j = 0; + ++$i; + } + last if $i >= $nrows; + _add_item($i, $j, $show_title_bar ? $c : $c + 1, + $wi, \@new_screen, \@new_mouse); + if ($c + 1 < $titems && $j + 1 < $ncols) { + $new_screen[$i][$j] .= $vars{separator}; + } + ++$j; + ++$c; + } + } + else { # column layout + ++$i if $show_title_bar; + for my $wi (@wi) { + if ($i >= $nrows) { + $i = 0; + ++$j; + } + last if $j >= $ncols; + _add_item($i, $j, $show_title_bar ? $c : $c + 1, + $wi, \@new_screen, \@new_mouse); + if ($c + $nrows < $titems) { + $new_screen[$i][$j] .= $vars{separator}; + } + ++$i; + ++$c; + } + } + my $step = $vars{seplen} + abs $vars{block}; + $i = 0; + my $str = Terminfo::sc . Terminfo::sgr0; + for (my $i = 0; $i < @new_screen; ++$i) { + for (my $j = 0; $j < @{$new_screen[$i]}; ++$j) { + if (defined $new_mouse[$i] && defined $new_mouse[$i][$j]) { + my $from = $j * $step; + $mouse_coords{$i}{$_} = $new_mouse[$i][$j] + for $from .. $from + abs $vars{block}; + } + next if defined $screen[$i] && defined $screen[$i][$j] + && $screen[$i][$j] eq $new_screen[$i][$j]; + $str .= Terminfo::cup($i, $j * $step) + . formats_to_ansi_basic($new_screen[$i][$j]) + . Terminfo::sgr0; + $str .= Terminfo::el if $j == $#{$new_screen[$i]} && (!$xenl || $j + 1 != $ncols); + } + } + for (@new_screen .. $screenHeight - 1) { + if (!@screen || defined $screen[$_]) { + $str .= Terminfo::cup($_, 0) . Terminfo::sgr0 . Terminfo::el; + } + } + $str .= Terminfo::rc; + safe_print $str; + @screen = @new_screen; + } + + sub handle_resize { + if (defined (my $r = safe_qx('stty size'))) { + ($screenHeight, $screenWidth) = split ' ', $r; + $resized = 0; + @screen = (); + $disp_update = 1; + if ($one_shot_integration == 2) { + $one_shot_resize--; + } + } + else { + } + } + + sub _build_keymap { + %c2w = reverse( %{$vars{key}}, %{$vars{key2}} ); + if (!grep { /^[+-]./ } keys %c2w) { + %c2w = (%c2w, map { ("-$_" => $c2w{$_}) } grep { !/^\^./ } keys %c2w); + } + %c2w = map { + my $key = $_; + s{^(-)?(\+)?(\^)?(.)}{ + join '', ( + ($1 ? "\e" : ''), + ($2 ? "\e\e" : ''), + ($3 ? "$4"^"@" : $4) + ) + }e; + $_ => $c2w{$key} + } keys %c2w; + @seqlist = sort { length $b <=> length $a } keys %c2w; + } + + sub _match_tmux { + length $ENV{TMUX} && exists $vars{irssienv}{tmux_srv} && length $vars{irssienv}{tmux_pane} + && $ENV{TMUX} eq $vars{irssienv}{tmux_srv} + } + + sub process_keys { + Encode::_utf8_on($keybuf); + my $win; + my $use_mouse; + my $maybe; + KEY: while (length $keybuf && !$maybe) { + $maybe = 0; + if ($keybuf =~ s/^\e\[M(.)(.)(.)//) { + @last_mouse = @mouse;# if @mouse && $mouse[0] < 64; + @mouse = map { -32 + ord } ($1, $2, $3); + $use_mouse = 1; + next KEY; + } + for my $s (@seqlist) { + if ($keybuf =~ s/^\Q$s//) { + $win = $c2w{$s}; + $use_mouse = 0; + next KEY; + } + elsif (length $keybuf < length $s && $s =~ /^\Q$keybuf/) { + $maybe = 1; + } + } + unless ($maybe) { + substr $keybuf, 0, 1, ''; + } + } + if ($use_mouse && @mouse && @last_mouse && + $mouse[2] == $last_mouse[2] && + $mouse[1] == $last_mouse[1] && + ($mouse[0] == 3 || $mouse[0] == 64 || $mouse[0] == 65)) { + if ($mouse[0] == 64) { + $win = 'up'; + } + elsif ($mouse[0] == 65) { + $win = 'down'; + } + elsif (exists $mouse_coords{$mouse[2] - 1}{$mouse[1] - 1}) { + $win = $mouse_coords{$mouse[2] - 1}{$mouse[1] - 1}; + } + elsif ($mouse[2] == 1 && $mouse[1] <= abs $vars{block}) { + $win = $last_mouse[0] != 0 ? 'last' : 'active'; + } + else { + } + } + if (defined $win) { + $win =~ s/^_//; + safe_print_sock("$win\n"); + if (!exists $ENV{AWL_AUTOFOCUS} || $ENV{AWL_AUTOFOCUS}) { + if (_match_tmux()) { + safe_qx("tmux selectp -t $vars{irssienv}{tmux_pane} 2>&1"); + } + elsif (exists $vars{irssienv}{xwinid}) { + safe_qx("wmctrl -ia $vars{irssienv}{xwinid} 2>/dev/null"); + } + } + } + Encode::_utf8_off($keybuf); + } + + sub check_integration { + return unless $vars{irssienv}; + return unless $sock && exists $vars{seplen} && exists $vars{block}; + if ($one_shot_integration == 1) { + my $nrows = $screenHeight - $vars{ha}; + my $ncols = ($vars{seplen} + abs $vars{block}) ? int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ) : 0; + my $items = ($show_title_bar ? 1 : 0) + @{$vars{win}//[]}; + my $dcols_required = $nrows ? int($items/$nrows) + !!($items%$nrows) : 0; + my $rows_required = $ncols ? int($items/$ncols) + !!($items%$ncols) : 0; + $rows_required = abs $vars{ml} + if ($vars{ml} < 0 || ($vars{ml} > 0 && $rows_required > $vars{ml})); + $dcols_required = abs $vars{mc} + if ($vars{mc} < 0 || ($vars{mc} > 0 && $dcols_required > $vars{mc})); + my $rows = $rows_required + $vars{ha}; + my $cols = ($dcols_required * ($vars{seplen} + abs $vars{block})) - $vars{seplen}; + if (_match_tmux()) { + # int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ); + my ($pos_flag, $before); + if ($integration_position eq 'left') { + $pos_flag = 'h'; + $before = 1; + } + elsif ($integration_position eq 'top') { + $pos_flag = 'v'; + $before = 1; + } + elsif ($integration_position eq 'right') { + $pos_flag = 'h'; + } + else { + $pos_flag = 'v'; + } + my @cmd = "joinp -d$pos_flag -s $ENV{TMUX_PANE} -t $vars{irssienv}{tmux_pane}"; + push @cmd, "swapp -d -t $ENV{TMUX_PANE} -s $vars{irssienv}{tmux_pane}" + if $before; + $cols = max($cols, 2); + $rows = max($rows, 2); + + safe_qx("tmux " . (join " \\\; ", @cmd) . " 2>&1"); + } + else { + $resized = 1; + #safe_qx("resize -s $screenHeight $cols 2>&1") + # if $cols > 0; + } + $one_shot_integration++; + if ($resized == 1) { + handle_resize(); + resize_integration(); + } + } + elsif ($one_shot_integration == 2) { + resize_integration(1); + } + } + + sub resize_integration { + return unless $one_shot_integration; + return unless ($one_shot_resize//0) < 0 || shift; + return if ($one_shot_resize//0) > 0; + + my $nrows = $screenHeight - $vars{ha}; + my $ncols = ($vars{seplen} + abs $vars{block}) ? int( ($screenWidth + $vars{seplen}) / ($vars{seplen} + abs $vars{block}) ) : 0; + my $items = ($show_title_bar ? 1 : 0) + @{$vars{win}//[]}; + my $dcols_required = $nrows ? (int($items/$nrows) + !!($items%$nrows)) : 0; + my $rows_required = $ncols ? int($items/$ncols) + !!($items%$ncols) : 0; + $rows_required = abs $vars{ml} + if ($vars{ml} < 0 || ($vars{ml} > 0 && $rows_required > $vars{ml})); + $dcols_required = abs $vars{mc} + if ($vars{mc} < 0 || ($vars{mc} > 0 && $dcols_required > $vars{mc})); + my $rows = $rows_required + $vars{ha}; + my $cols = ($dcols_required * ($vars{seplen} + abs $vars{block})) - $vars{seplen}; + if (_match_tmux()) { + my $pos_flag; + my $before = 0; + if ($integration_position eq 'left') { + $pos_flag = 'h'; + $before = 1; + } + elsif ($integration_position eq 'top') { + $pos_flag = 'v'; + $before = 1; + } + elsif ($integration_position eq 'right') { + $pos_flag = 'h'; + } + else { + $pos_flag = 'v'; + } + my @cmd; + # hard tmux limits + $cols = max($cols, 2); + $rows = max($rows, 2); + if ($pos_flag eq 'h' && $cols != $screenWidth) { + my $change = $screenWidth - $cols; + my $dir = ($before ^ ($change<0)) ? 'L' : 'R'; + push @cmd, "resizep -$dir -t $ENV{TMUX_PANE} @{[abs $change]}"; + #push @cmd, "resizep -x $cols -t $ENV{TMUX_PANE}"; + $one_shot_resize = 1; + } + if ($pos_flag eq 'v' && $rows != $screenHeight) { + #push @cmd, "resizep -y $rows -t $ENV{TMUX_PANE}"; + my $change = $screenHeight - $rows; + my $dir = ($before ^ ($change<0)) ? 'U' : 'D'; + push @cmd, "resizep -$dir -t $ENV{TMUX_PANE} @{[abs $change]}"; + $one_shot_resize = 1; + } + + safe_qx("tmux " . (join " \\\; ", @cmd) . " 2>&1") + if @cmd; + } + else { + $cols = max($cols, 1); + $rows = max($rows, 1); + unless ($nrows > $ncols) { # line layout + if ($rows != $screenHeight) { + safe_qx("resize -s $rows $screenWidth 2>&1"); + $one_shot_resize = 1; + } + } + else { + if ($cols != $screenWidth) { + safe_qx("resize -s $screenHeight $cols 2>&1"); + $one_shot_resize = 1; + } + } + } + if ($resized == 1) { + handle_resize(); + } + } + + sub init_integration { + return unless $one_shot_integration; + if (_match_tmux()) { + } + else { + } + safe_print("\e]2;".(uc ::setc())."\e\\"); + } + + sub main { + require Getopt::Std; + my %opts; + Getopt::Std::getopts('1p:', \%opts); + my $one_shot = $opts{1}; + $integration_position = $opts{p}; + $one_shot_integration = 0+!!$one_shot; + #shift if @_ && $_[0] eq '--'; + &init; + $show_title_bar = 0 if $ENV{AWL_NOTITLE}; + init_integration(); + until ($got_int) { + $timeout = undef; + if ($resized) { + if ($resized == 1) { + $timeout = 1; + $resized++; + } + else { + handle_resize(); + resize_integration(); + } + } + unless ($sock || $timeout) { + connect_it(); + } + $timeout ||= RECONNECT_TIME unless $sock; + update_screen() if $disp_update; + SELECT: while (my @read = $loop->can_read($timeout)) { + for my $fh (@read) { + if ($fh == \*STDIN) { + if (read STDIN, my $buf, BLOCK_SIZE) { + do { + $keybuf .= $buf; + } while read STDIN, $buf, BLOCK_SIZE; + } + else { + $got_int = 1; + last SELECT; + } + } + else { + if ($fh->read(my $buf, BLOCK_SIZE)) { + do { + $rcvbuf .= $buf; + } while $fh->read($buf, BLOCK_SIZE); + } + else { + $disp_update = 1; + remove_conn($fh); + if ($one_shot) { + $got_int = 1; + last SELECT; + } + $timeout ||= RECONNECT_TIME; + } + } + } + $disp_update |= process_recv() if length $rcvbuf; + process_keys() if length $keybuf; + check_integration() if $one_shot; + update_screen() if $disp_update; + } + continue { + } + } + end_prog(); + } +} + +1; + +# Changelog +# ========= +# 1.11 +# - fix compat with Irssi 1.4 +# +# 1.10 +# - add /set awl_custom_key_re, to display custom keys in the $Q +# expando. requested by madduck +# +# 1.9.1 +# - fix crash on mouse click +# +# 1.9 +# - add %Z support to viewer +# +# 1.8 +# - use string_width in Irssi 1.2.0 +# +# 1.7 +# - fix crash on invalid /set awl_sort, introduced in 1.6, reported by +# tpetazzoni +# - delay viewer initialisation +# - improve race condition on tmux resize integration +# +# 1.6 +# - add detach setting to hide windows +# - fix race condition when loading the script, reported by madduck +# - improve compatibility with irssi 1.2 +# - add special value lru to awl_sort to sort windows by usage +# +# 1.5 +# - improve compat. with sideways splits +# +# 1.4 +# - fix line wrapping in some themes, reported by justanotherbody +# - fix named window key detection, reported by madduck +# - make title (in viewer and shared_sbar) configurable +# +# 1.3 +# - workaround for irssi issue #572 +# +# 1.2 +# - new format to choose abbreviation character +# +# 1.1 +# - infinite loop on shortening certain window names reported by Kalan +# +# 1.0 +# - new awl_viewer_launch setting and an array of related settings +# - fixed regression bug /exec -interactive +# - fixed some warnings in perl 5.10 reported by kl3 +# - workaround for crash due to infinite recursion in irssi's Perl +# error handling +# +# 0.9 +# - fix endless loop in awin detection code! +# - correct colour swap in awl_viewer +# - fix passing of alternate socket path to the viewer +# - potential undefinedness in mouse refnum hinted at by Canopus +# - fixed regression bug /exec -interactive +# - add case-insensitive modifier to awl_sort +# - run custom_xform on awl_prefer_name also +# - avoid inconsistent active window state after awin detection +# reported by ss +# - revert %9-hack in the viewer prompted by discussion with pierrot +# - fix new warning in perl 5.22 +# +# 0.8 +# - replace fifo mode with external viewer script +# - remove bundled cpan modules +# - work around bogus irssi warning +# - improve mouse support +# - workaround for broken cumode in irssi 0.8.15 +# - fix handling of non-meta windows (uninitialized warning) +# - add 256 colour support, strip true colour codes +# - fix totally bogus $N padding reported by Ed S. +# - make /window goto #name mappings work but ignore non-existant ones +# - improve incomplete reads reported by bcode +# - fix single % in awl_viewer reported by bcode +# - add support for key bindings by nike and ferret +# - coerce utf8 key binds +# - add settings: custom_xform, last_line_shade, hide_name_data +# - abbreviations were broken in some cases +# - fix some misuse of / as cmdchar in mouse script reported by bcode +# - add shared status bar mode +# - ${type} variables for custom_xform setting +# - crash if custom_xform had runtime error +# - update sorting documentation +# - fix odd case in size calculation noted by lasers +# - add missing font styles to the viewer reported by ishanyx +# - add italic +# +# 0.7g +# - remove screen support and replace it with fifo support +# - add double-width support to the shortener +# - correct documentation regarding $T vs. display_header +# - add missing refresh for window item changed (thanks vague) +# - add visible windows +# - add exemptions for active window +# - workaround for hiding the window changes from trackbar +# - hack to force 16colours in screen mode +# - remember last window (reported by earthnative) +# - wrong window focus on new queries (reported by emsid) +# - dataloss bug on trying to remember last window +# +# 0.6d+ +# - add support for network headers +# - fixed regression bug /exec -interactive +# +# 0.6ca+ +# - add screen support (from nicklist.pl) +# - names can now have a max length and window names can be used +# - fixed a bug with block display in screen mode and status bar mode +# - added space handling to ir_fe and removed it again +# - now handling formats on my own +# - started to work on $tag display +# - added warning about missing sb_act_none abstract leading to +# - display*active settings +# - added warning about the bug in awl_display_(no)key_active settings +# - mouse hack +# +# 0.5d +# - add setting to also hide the last status bar if empty (awl_all_disable) +# - reverted to old utf8 code to also calculate broken utf8 length correctly +# - simplified dealing with status bars in wlreset +# - added a little tweak for the renamed term_type somewhere after Irssi 0.8.9 +# - fixed bug in handling channel #$$ +# - reset background colour at the beginning of an entry +# +# 0.4d +# - fixed order of disabling status bars +# - several attempts at special chars, without any real success +# and much more weird new bugs caused by this +# - setting to specify sort order +# - reduced timeout values +# - added awl_hide_data +# - make it so the dynamic sub is actually deleted +# - fix a bug with removing of the last separator +# - take into consideration parse_special +# +# 0.3b +# - automatically kill old status bars +# - reset on /reload +# - position/placement settings +# +# 0.2 +# - automated retrieval of key bindings (thanks grep.pl authors) +# - improved removing of status bars +# - got rid of status chop +# +# 0.1 +# - Based on chanact.pl which was apparently based on lightbar.c and +# nicklist.pl with various other ideas from random scripts. diff --git a/.irssi/scripts/mouse.pl b/.irssi/scripts/mouse.pl new file mode 100644 index 0000000..d9debc7 --- /dev/null +++ b/.irssi/scripts/mouse.pl @@ -0,0 +1,168 @@ +# See http://wouter.coekaerts.be/site/irssi/mouse +# based on irssi mouse patch by mirage: http://darksun.com.pt/mirage/irssi/ + +# Copyright (C) 2005-2009 Wouter Coekaerts <wouter@coekaerts.be> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +use strict; +use Irssi qw(signal_emit settings_get_str active_win signal_stop settings_add_str settings_add_bool settings_get_bool signal_add signal_add_first); +use Math::Trig; + +use vars qw($VERSION %IRSSI); + +$VERSION = '1.1.2'; +%IRSSI = ( + authors => 'Wouter Coekaerts', + contact => 'wouter@coekaerts.be', + name => 'mouse', + description => 'control irssi using mouse clicks and gestures', + license => 'GPLv2 or later', + url => 'http://wouter.coekaerts.be/irssi/', + changed => '2021-03-05', +); + +my @BUTTONS = ('', '_middle', '_right'); + +my $mouse_xterm_status = -1; # -1:off 0,1,2:filling mouse_xterm_combo +my @mouse_xterm_combo = (3, 0, 0); # 0:button 1:x 2:y +my @mouse_xterm_previous; # previous contents of mouse_xterm_combo + +sub mouse_enable { + print STDERR "\e[?1000h"; # start tracking +} + +sub mouse_disable { + print STDERR "\e[?1000l"; # stop tracking +} + +# Handle mouse event (button press or release) +sub mouse_event { + my ($b, $x, $y, $oldb, $oldx, $oldy) = @_; + my ($xd, $yd); + my ($distance, $angle); + + # uhm, in the patch the scrollwheel didn't work for me, but this does: + if ($b == 64) { + cmd("mouse_scroll_up"); + } elsif ($b == 65) { + cmd("mouse_scroll_down") + } + + # proceed only if a button is being released + return if ($b != 3); + + return unless (0 <= $oldb && $oldb <= 2); + my $button = $BUTTONS[$oldb]; + + # if it was a mouse click of the left button (press and release in the same position) + if ($x == $oldx && $y == $oldy) { + cmd("mouse" . $button . "_click"); + return; + } + + # otherwise, find mouse gestures + $xd = $x - $oldx; + $yd = -1 * ($y - $oldy); + $distance = sqrt($xd*$xd + $yd*$yd); + # ignore small gestures + if ($distance < 3) { + return; + } + $angle = asin($yd/$distance) * 180 / 3.14159265358979; + if ($angle < 20 && $angle > -20 && $xd > 0) { + if ($distance <= 40) { + cmd("mouse" . $button . "_gesture_right"); + } else { + cmd("mouse" . $button . "_gesture_bigright"); + } + } elsif ($angle < 20 && $angle > -20 && $xd < 0) { + if ($distance <= 40) { + cmd("mouse" . $button . "_gesture_left"); + } else { + cmd("mouse" . $button . "_gesture_bigleft"); + } + } elsif ($angle > 40) { + cmd("mouse" . $button . "_gesture_up"); + } elsif ($angle < -40) { + cmd("mouse" . $button . "_gesture_down"); + } +} + +# executes the command configured in the given setting +sub cmd +{ + my ($setting) = @_; + signal_emit("send command", settings_get_str($setting), active_win->{'active_server'}, active_win->{'active'}); +} + + +signal_add_first("gui key pressed", sub { + my ($key) = @_; + if ($mouse_xterm_status != -1) { + if ($mouse_xterm_status == 0 && ($mouse_xterm_previous[0] != $mouse_xterm_combo[0])) { # if combo is starting, and previous what not a move (button not changed) + @mouse_xterm_previous = @mouse_xterm_combo; + } + $mouse_xterm_combo[$mouse_xterm_status] = $key-32; + $mouse_xterm_status++; + if ($mouse_xterm_status == 3) { + $mouse_xterm_status = -1; + # match screen coordinates + $mouse_xterm_combo[1]--; + $mouse_xterm_combo[2]--; + mouse_event($mouse_xterm_combo[0], $mouse_xterm_combo[1], $mouse_xterm_combo[2], $mouse_xterm_previous[0], $mouse_xterm_previous[1], $mouse_xterm_previous[2]); + } + signal_stop(); + } +}); + +sub UNLOAD { + mouse_disable(); +} + +if ($ENV{"TERM"} !~ /^rxvt|screen|xterm|tmux(-(256)?(color|kitty))?$/) { + die "Your terminal doesn't seem to support this."; +} + +mouse_enable(); + +Irssi::command("/^bind meta-[M /mouse_xterm"); # FIXME evil +Irssi::command_bind("mouse_xterm", sub {$mouse_xterm_status = 0;}); +Irssi::command_bind 'mouse' => sub { + my ($data, $server, $item) = @_; + $data =~ s/\s+$//g; + Irssi::command_runsub('mouse', $data, $server, $item); +}; + +# temporarily disable mouse handling. Useful for copy-pasting without touching the keyboard (pressing shift) +Irssi::command_bind 'mouse tempdisable' => sub { + my ($data, $server, $item) = @_; + my $seconds = ($data eq '') ? 5 : $data; # optional argument saying how many seconds, defaulting to 5 + mouse_disable(); + Irssi::timeout_add_once($seconds * 1000, 'mouse_enable', undef); # turn back on after $second seconds +}; + +for my $button (@BUTTONS) { + settings_add_str("lookandfeel", "mouse" . $button . "_click", "/mouse tempdisable 5"); + settings_add_str("lookandfeel", "mouse" . $button . "_gesture_up", "/window last"); + settings_add_str("lookandfeel", "mouse" . $button . "_gesture_down", "/window goto active"); + settings_add_str("lookandfeel", "mouse" . $button . "_gesture_left", "/window prev"); + settings_add_str("lookandfeel", "mouse" . $button . "_gesture_bigleft", "/eval window prev;window prev"); + settings_add_str("lookandfeel", "mouse" . $button . "_gesture_right", "/window next"); + settings_add_str("lookandfeel", "mouse" . $button . "_gesture_bigright", "/eval window next;window next"); +} + +settings_add_str("lookandfeel", "mouse_scroll_up", "/scrollback goto -10"); +settings_add_str("lookandfeel", "mouse_scroll_down", "/scrollback goto +10"); diff --git a/.irssi/scripts/nm2.pl b/.irssi/scripts/nm2.pl new file mode 100644 index 0000000..b553bf2 --- /dev/null +++ b/.irssi/scripts/nm2.pl @@ -0,0 +1,569 @@ +use Irssi; +use strict; +use v5.14; +use List::Util qw(min max); +use Hash::Util qw(lock_keys); + +our $VERSION = '2.1'; # a42b713aaa38823 +our %IRSSI = ( + authors => 'Nei', + contact => 'Nei @ anti@conference.jabber.teamidiot.de', + url => "http://anti.teamidiot.de/", + name => 'nm2', + description => 'right aligned nicks depending on longest nick', + license => 'GPL v2', +); + +# based on bc-bd's original nm.pl +# +# use a ** nickcolor_expando ** script for nick colors! +# +# why is there no right_mode? you can do that in your theme! + +# Options +# ======= +# /set neat_dynamic <ON|OFF> +# * whether the width should be dynamically chosen on each incoming +# message +# +# /set neat_shrink <ON|OFF> +# * whether shrinking of the width is allowed, or only growing +# +# /set neat_staircase_shrink <ON|OFF> +# * whether shrinking should be done one character at a time +# +# The following styles decide if the nick is left/right aligned and +# where the colour/mode goes, they're a bit complex... +# put the desired indicator(s) between the appropriate "," and the +# default format of the public messages or actions will be rewritten +# appropriately. +# This can be used to align the nick left or right, before or after +# the nick brackets and before or between the nickmode (by using the +# pad on the correct place). To change the mode from left of the nick +# to right of the nick, you need to modify the abstracts in your theme +# however. +# By placing the colour at the end, you can even colour the message +# text in the nick colour, however it might be broken if there are +# other colour codes used inside the message or by scripts. +# +# /format neat_style , , , , , , , , +# î î î î î î î î î +# p: pad | | | | | | | | `before message +# c: colour | | | | | | | `-after msgchannel +# t: truncate indicator | | | | | | `-before msgchannel +# | | | | | `-after nick +# | | | | `-before nick +# | | | `-after mode +# | | `-before mode +# | `-before msgnick +# `-none +# +# /format neat_action_style , , , , +# î î î î î +# p: pad | | | | `-before message +# c: colour | | | `-after nick +# t: truncate indicator | | `-before nick +# | `-before action +# `-none +# +# /format neat_pad_char <char> +# * the character(s) used for padding +# +# /format neat_truncate_char +# * the format or character to indicate that nick was truncated +# +# /format neat_notruncate_char +# * the format or character to indicate that nick NOT was truncated +# +# /format neat_customize_modes @@ | ++ | ? +# * a |-separated mapping of mode prefixes and their rendition, can be +# used to replace or colourise them +# +# /set neat_color_hinick <ON|OFF> +# * whether to use colours in hilighted messages +# +# /set neat_color_menick <ON|OFF> +# * whether to use colours in hilight_nick_matches +# +# /set neat_truncate_nick <ON|OFF> +# * whether to truncate overlong nicks +# +# /set neat_custom_modes <ON|OFF> +# * whether to enable the use of neat_customize_modes format +# +# /set neat_maxlength <number> +# * number : (maximum) length to use for nick padding +# +# /set neat_melength <number> +# * number : width to substract from maxlength for /me padding +# +# /set neat_history <number> +# * number : number of formatted lines to remember for dynamic mode +# + +my @action_protos = qw(irc silc xmpp); +my (%histories, %S, @style, @astyle, %format_ok, %cmmap); + +my $align_expando = ''; +my $trunc_expando = ''; +my $cumode_expando = ''; + +my $format_re = qr/ %(?=[}%{]) + | %[04261537kbgcrmywKBGCRMYWU9_8I:|FnN>#pP[] + | %[Zz][[:xdigit:]]{6} + | %[Xx](?i:0[a-f]|[1-6][0-9a-z]|7[a-x]) /x; + +sub update_expando { + my ($mode, $server, $target, $nick, $space) = @_; + my $t_add; + if (exists $Irssi::Script::{'realnames::'} + && (my $code = 'Irssi::Script::realnames'->can('_get_nick_chan'))) { + if (my $i = $code->($server, $target, $nick)) { + $nick = $i->{n}{realname} + if length $i->{n}{realname}; + } + } + my $nl = length $nick; + my $pad_len = max(0, $space - $nl); + if ($S{truncate_nick}) { + if (($mode >= 4 && $S{trunc_in_anick}) + || ($mode < 4 && $S{trunc_in_nick})) { + $t_add = $S{tnolen}; + } + if ($nl + $t_add > $space) { + $trunc_expando = format_expand($S{tyes_char}); + $t_add = $S{tyeslen} if defined $t_add; + } + else { + $trunc_expando = format_expand($S{tno_char}); + } + $pad_len = max(0, $pad_len - $t_add) if $t_add; + } + else { + $trunc_expando = ''; + } + if ($pad_len) { + my @subs = split /($format_re)/, $S{pad_char} x $pad_len; + $align_expando = ''; + my $clen = 0; + while (@subs) { + my ($tx, $fmt) = splice @subs, 0, 2; + my $txlen = length $tx // 0; + $align_expando .= substr $tx, 0, ($pad_len - $clen) if defined $tx; + $clen += $txlen; + $align_expando .= $fmt if defined $fmt; + last if $clen >= $pad_len; + } + $align_expando = format_expand($align_expando.'%n'); + } + else { + $align_expando = ''; + } + return $t_add; +} + +sub prnt_clear_levels { + my ($dest) = @_; + clear_ref() if $dest->{level} + & (MSGLEVEL_PUBLIC|MSGLEVEL_MSGS|MSGLEVEL_ACTIONS|MSGLEVEL_DCCMSGS|MSGLEVEL_NOTICES); +} + +sub clear_ref { + $trunc_expando = $align_expando = $cumode_expando = ''; +} + +sub expando_nickalign { $align_expando } +sub expando_nicktrunc { $trunc_expando } +sub expando_nickcumode { $cumode_expando } + +Irssi::expando_create('nickalign', \&expando_nickalign, { + 'message public' => 'none', + 'message own_public' => 'none', + 'message private' => 'none', + 'message own_private' => 'none', + (map { ("message $_ action" => 'none', + "message $_ own_action" => 'none') + } @action_protos), + }); +Irssi::expando_create('nicktrunc', \&expando_nicktrunc, { + 'message public' => 'none', + 'message own_public' => 'none', + 'message private' => 'none', + 'message own_private' => 'none', + (map { ("message $_ action" => 'none', + "message $_ own_action" => 'none') + } @action_protos), + }); +Irssi::expando_create('nickcumode', \&expando_nickcumode, { + 'message public' => 'none', + 'message own_public' => 'none', + 'message private' => 'none', + 'message own_private' => 'none', + (map { ("message $_ action" => 'none', + "message $_ own_action" => 'none') + } @action_protos), + }); + +sub init_hist { + my ($server, $target) = @_; + if (my $ch = $server->channel_find($target)) { + [ max map { length } map { $_->{nick} } $ch->nicks ] + } + else { + [ max map { length } $server->{nick}, $target ] + } +} + +my %em = ( + p => '$nickalign', + c => '$nickcolor', + t => '$nicktrunc', + m => '$nickcumode', + ); + +my %formats = ( + own_action => [5, '{ownaction ', '$0','}','$1' ], + action_public => [4, '{pubaction ', '$0','}','$1' ], + action_private => [4, '{pvtaction ', '$0','}','$2' ], + action_private_query => [4, '{pvtaction_query ','$0','}','$2' ], + # * * * # * * + + own_msg_private_query => [3, '{ownprivmsgnick ', '' ,'{ownprivnick ','$2','}','' ,'}','$1' ], + msg_private_query => [2, '{privmsgnick ' ,'' ,'' ,'$0','' ,'' ,'}','$2' ], + own_msg => [1, '{ownmsgnick ' ,'$2',' {ownnick ' ,'$0','}','' ,'}','$1' ], + own_msg_channel => [1, '{ownmsgnick ' ,'$3',' {ownnick ' ,'$0','}','{msgchannel $1}','}','$2' ], + pubmsg_me => [0, '{pubmsgmenick ' ,'$2',' {menick ' ,'$0','}','' ,'}','$1' ], + pubmsg_me_channel => [0, '{pubmsgmenick ' ,'$3',' {menick ' ,'$0','}','{msgchannel $1}','}','$2' ], + pubmsg_hilight => [0, '{pubmsghinick $0 ','$3',' ' ,'$1', '','', ,'}','$2' ], + pubmsg_hilight_channel => [0, '{pubmsghinick $0 ','$4',' ' ,'$1', '','{msgchannel $2}','}','$3' ], + pubmsg => [0, '{pubmsgnick ' ,'$2',' {pubnick ' ,'$0','}','' ,'}','$1' ], + pubmsg_channel => [0, '{pubmsgnick ' ,'$3',' {pubnick ' ,'$0','}','{msgchannel $1}','}','$2' ], + # * * * * * # * * * * + ); + +sub reformat_format { + Irssi::signal_remove('command format', 'update_formats'); + Irssi::signal_remove('theme changed' => 'update_formats'); + %format_ok = () unless @_; + my ($mode, $server, $target, $nick, $size) = @_; + for my $fmt (keys %formats) { + next if defined $mode && $formats{$fmt}[0] != $mode; + + my @fs = @{ $formats{$fmt} }; + + my $ls; + if (defined $mode) { + $ls = $size; + } + else { + $ls = $fs[0] < 4 ? $S{max} : max(0, $S{max} - $S{melength}); + } + next if exists $format_ok{$fmt} && $format_ok{$fmt} == $ls; + + if ($S{truncate_nick} && $ls) { + $fs[ $fs[0] < 4 ? 4 : 2 ] =~ s/\$/\$[.$ls]/; + } + if ($S{custom_modes} && $fs[0] < 4) { + $fs[2] =~ s/\$\K\d/nickcumode/; + } + my $s; + local $em{c} = '' + if ($fs[1] =~ /menick/ && !$S{color_menick}) + || ($fs[1] =~ /hinick/ && !$S{color_hinick}); + my $sr = $fs[0] >= 4 ? \@astyle : \@style; + for my $i (1..$#fs) { + $s .= ($sr->[$i] =~ s/(.)/$em{$1}/gr) if defined $sr->[$i]; + $s .= $fs[$i]; + } + Irssi::command("^format $fmt $s"); + $format_ok{$fmt} = $ls; + } + Irssi::signal_add_last({ + 'theme changed' => 'update_formats', + 'command format' => 'update_formats', + }); +} + +sub update_nm { + my ($mode, $server, $target, $nick) = @_; + my $tg = $server->{tag}; + if (my $ch = $server->channel_find($target)) { + $target = $ch->{name}; + my $nickobj = $ch->nick_find($nick); + if ($nickobj) { + $nick = $nickobj->{nick}; + my $mode = substr $nickobj->{prefixes}.' ', 0, 1; + $cumode_expando = exists $cmmap{$mode} ? format_expand($cmmap{$mode}) : $mode; + } + else { + $cumode_expando = ''; + } + } + elsif (my $q = $server->query_find($target)) { + $target = $q->{name}; + } + + my $longest; + if ($S{dynamic}) { + my $hist = $histories{"$tg/$target"} ||= init_hist($server, $target); + my $last = $histories{"$tg/$target/last"} || 1; + unshift @$hist, length $nick; + if (@$hist > 2*$S{history}) { + splice @$hist, $S{history}; + } + my @add; + unless ($S{shrink}) { + push @add, $last; + } + if ($S{staircase}) { + push @add, $last - 1 + } + $longest = $histories{"$tg/$target/last"} = max(@$hist, @add); + + if ($S{max} && ($S{max} < $longest || !$S{shrink})) { + $longest = $S{max}; + } + } + else { + $longest = $S{max}; + } + + my $size = $mode < 4 ? $longest : max(0, $longest - $S{melength}); + my $t_add = update_expando($mode, $server, $target, $nick, $size); + $size = max(0, $size - $t_add) if defined $t_add; + if ($S{dynamic}) { + reformat_format($mode, $server, $target, $nick, $size); + } +} + +sub sig_setup { + my %old_S = %S; + $S{history} = Irssi::settings_get_int('neat_history'); + $S{max} = Irssi::settings_get_int('neat_maxlength'); + $S{melength} = Irssi::settings_get_int('neat_melength'); + + $S{dynamic} = Irssi::settings_get_bool('neat_dynamic'); + $S{shrink} = Irssi::settings_get_bool('neat_shrink'); + $S{staircase} = Irssi::settings_get_bool('neat_staircase_shrink'); + + $S{color_hinick} = Irssi::settings_get_bool('neat_color_hinick'); + $S{color_menick} = Irssi::settings_get_bool('neat_color_menick'); + $S{truncate_nick} = Irssi::settings_get_bool('neat_truncate_nick'); + $S{custom_modes} = Irssi::settings_get_bool('neat_custom_modes'); + + if (!defined $old_S{dynamic} || $old_S{dynamic} != $S{dynamic}) { + %histories = (); + reformat_format(); + } + elsif ($old_S{max} != $S{max} || $old_S{melength} != $S{melength} + || $old_S{color_hinick} != $S{color_hinick} || $old_S{color_menick} != $S{color_menick} + || $old_S{truncate_nick} != $S{truncate_nick} || $old_S{custom_modes} != $S{custom_modes}) { + reformat_format(); + } +} + +sub update_formats { + my $was_style = "@style"; + $S{style} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_style'); + my $was_action_style = "@astyle"; + $S{action_style} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_action_style'); + $S{pad_char} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_pad_char'); + $S{tno_char} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_notruncate_char'); + $S{tnolen} = length($S{tno_char} =~ s/$format_re//gr); + $S{tyeslen} = length($S{tyes_char} =~ s/$format_re//gr); + $S{tyes_char} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_truncate_char'); + @style = map { y/pct//cd; $_ } split /,/, $S{style}; + @astyle = map { y/pctm//cd; $_ } split /,/, $S{action_style}; + $S{trunc_in_nick} = grep { /t/ } @style[2..min($#style, 6)]; + $S{trunc_in_anick} = grep { /t/ } @astyle[2..min($#astyle, 3)]; + my $custom_modes = Irssi::current_theme->get_format(__PACKAGE__, 'neat_custom_modes'); + %cmmap = map { (substr $_, 0, 1), (substr $_, 1) } $custom_modes =~ /(?:^\s?|\G\s?\|\s?)((?!\s\|)(?:[^\\|[:space:]]|\\.|\s(?!\||$))*)/sg; + if ($was_style ne "@style" || $was_action_style ne "@astyle") { + reformat_format(); + } +} + +{ + my %format2control = ( + 'F' => "\cDa", '_' => "\cDc", '|' => "\cDe", '#' => "\cDi", "n" => "\cDg", "N" => "\cDg", + 'U' => "\c_", '8' => "\cV", 'I' => "\cDf", + ); + my %bg_base = ( + '0' => '0', '4' => '1', '2' => '2', '6' => '3', '1' => '4', '5' => '5', '3' => '6', '7' => '7', + 'x08' => '8', 'x09' => '9', 'x0a' => ':', 'x0b' => ';', 'x0c' => '<', 'x0d' => '=', 'x0e' => '>', 'x0f' => '?', + ); + my %fg_base = ( + 'k' => '0', 'b' => '1', 'g' => '2', 'c' => '3', 'r' => '4', 'm' => '5', 'p' => '5', 'y' => '6', 'w' => '7', + 'K' => '8', 'B' => '9', 'G' => ':', 'C' => ';', 'R' => '<', 'M' => '=', 'P' => '=', 'Y' => '>', 'W' => '?', + ); + my @ext_colour_off = ( + '.', '-', ',', + '+', "'", '&', + ); + sub format_expand { + $_[0] =~ s{%(Z.{6}|z.{6}|X..|x..|.)}{ + my $c = $1; + if (exists $format2control{$c}) { + $format2control{$c} + } + elsif (exists $bg_base{$c}) { + "\cD/$bg_base{$c}" + } + elsif (exists $fg_base{$c}) { + "\cD$fg_base{$c}/" + } + elsif ($c =~ /^[{}%]$/) { + $c + } + elsif ($c =~ /^(z|Z)([[:xdigit:]]{2})([[:xdigit:]]{2})([[:xdigit:]]{2})$/) { + my $bg = $1 eq 'z'; + my (@rgb) = map { hex $_ } $2, $3, $4; + my $x = $bg ? 0x1 : 0; + my $out = "\cD" . (chr -13 + ord '0'); + for (my $i = 0; $i < 3; ++$i) { + if ($rgb[$i] > 0x20) { + $out .= chr $rgb[$i]; + } + else { + $x |= 0x10 << $i; $out .= chr 0x20 + $rgb[$i]; + } + } + $out .= chr 0x20 + $x; + $out + } + elsif ($c =~ /^(x)(?:0([[:xdigit:]])|([1-6])(?:([0-9])|([a-z]))|7([a-x]))$/i) { + my $bg = $1 eq 'x'; + my $col = defined $2 ? hex $2 + : defined $6 ? 232 + (ord lc $6) - (ord 'a') + : 16 + 36 * ($3 - 1) + (defined $4 ? $4 : 10 + (ord lc $5) - (ord 'a')); + if ($col < 0x10) { + my $chr = chr $col + ord '0'; + "\cD" . ($bg ? "/$chr" : "$chr/") + } + else { + "\cD" . $ext_colour_off[($col - 0x10) / 0x50 + $bg * 3] . chr (($col - 0x10) % 0x50 - 1 + ord '0') + } + } + else { + "%$c" + } + }ger; + } +} + +sub init { + update_formats(); + sig_setup(); + lock_keys(%S); + print "nm2 experimental version, please report issues. thanks!" +} + +Irssi::settings_add_bool('misc', 'neat_dynamic', 1); +Irssi::settings_add_bool('misc', 'neat_shrink', 1); +Irssi::settings_add_bool('misc', 'neat_staircase_shrink', 0); + +Irssi::settings_add_bool('misc', 'neat_color_hinick', 0); +Irssi::settings_add_bool('misc', 'neat_color_menick', 0); +Irssi::settings_add_bool('misc', 'neat_truncate_nick', 1); +Irssi::settings_add_bool('misc', 'neat_custom_modes', 0); + +Irssi::settings_add_int('misc', 'neat_maxlength', 0); +Irssi::settings_add_int('misc', 'neat_melength', 2); +Irssi::settings_add_int('misc', 'neat_history', 50); + +Irssi::signal_add('setup changed' => 'sig_setup'); +Irssi::signal_add_last({ + 'setup reread' => 'sig_setup', + 'theme changed' => 'update_formats', + 'command format' => 'update_formats', + }); + +Irssi::theme_register([ + 'neat_style' => ' , , p , , c , t , , , ', + 'neat_action_style' => ' , p , , t , ', + 'neat_pad_char' => '%K.', + 'neat_truncate_char' => '%m+', + 'neat_notruncate_char' => '', + 'neat_custom_modes' => '&%B&%n | @%g@%n | +%y+%n', + ]); + +Irssi::signal_add_first({ + 'message public' => sub { + my ($server, $msg, $nick, $address, $target) = @_; + update_nm(0, $server, $target, $nick); + }, + 'message private' => sub { + my ($server, $msg, $nick, $address) = @_; + update_nm(2, $server, $nick, $nick); + }, + (map { ("message $_ action" => sub { + my ($server, $msg, $nick, $address, $target) = @_; + update_nm(4, $server, $target, $nick); + }) } qw(irc silc)), + 'message xmpp action' => sub { + return unless @_; + my ($server, $msg, $nick, $target) = @_; + update_nm(4, $server, $target, $nick); + }, + }); + +sub channel_nick { + my ($server, $target) = @_; + ($server->channel_find($target)||+{ownnick=>$server})->{ownnick}{nick} +} + +Irssi::signal_add_first({ + 'message own_public' => sub { + my ($server, $msg, $target) = @_; + update_nm(1, $server, $target, channel_nick($server, $target)); + }, + 'message own_private' => sub { + my ($server, $msg, $target) = @_; + update_nm(3, $server, $target, $server->{nick}); + }, + (map { ("message $_ own_action" => sub { + my ($server, $msg, $target) = @_; + update_nm(5, $server, $target, $server->{nick}); + }) } qw(irc silc)), + 'message xmpp own_action' => sub { + return unless @_; + my ($server, $msg, $target) = @_; + update_nm(5, $server, $target, channel_nick($server, $target)); + }, + }); +Irssi::signal_add_last({ + 'channel destroyed' => sub { + my ($channel) = @_; + delete $histories{ $channel->{server}{tag} . '/' . $channel->{name} }; + delete $histories{ $channel->{server}{tag} . '/' . $channel->{name} . '/last' }; + }, + 'query destroyed' => sub { + my ($query) = @_; + delete $histories{ $query->{server}{tag} . '/' . $query->{name} }; + delete $histories{ $query->{server}{tag} . '/' . $query->{name} . '/last' }; + }, + 'query nick changed' => sub { + my ($query, $old_nick) = @_; + delete $histories{ $query->{server}{tag} . '/' . $old_nick }; + delete $histories{ $query->{server}{tag} . '/' . $old_nick . '/last' }; + }, + 'query server changed' => sub { + my ($query, $old_server) = @_; + delete $histories{ $old_server->{tag} . '/' . $query->{name} }; + delete $histories{ $old_server->{tag} . '/' . $query->{name} . '/last' }; + } + }); +Irssi::signal_add({ + 'print text' => 'prnt_clear_levels', +}); + +init(); + +# Changelog +# ========= +# 2.1 - support realnames script +# +# 2.0 +# - fix crash if xmpp action signal is not registered (just ignore it) +# - do not grow either when using no-shrink with maxlength +# - hopefully fix alignment in xmpp muc diff --git a/.irssi/scripts/tmux-nicklist-portable.pl b/.irssi/scripts/tmux-nicklist-portable.pl new file mode 100644 index 0000000..e0c6920 --- /dev/null +++ b/.irssi/scripts/tmux-nicklist-portable.pl @@ -0,0 +1,432 @@ +# based on the nicklist.pl script +################################################################################ +# tmux_nicklist.pl +# This script integrates tmux and irssi to display a list of nicks in a +# vertical right pane with 20% width. Right now theres no configuration +# or setup, simply initialize the script with irssi and by default you +# will get the nicklist for every channel(customize by altering +# the regex in /set nicklist_channel_re) +# +# /set nicklist_channel_re <regex> +# * only show on channels matching this regular expression +# +# /set nicklist_max_users <num> +# * only show when the channel has so many users or less (0 = always) +# +# /set nicklist_smallest_main <num> +# * only show when main window is larger than this (0 = always) +# +# /set nicklist_pane_width <num> +# * width of the nicklist pane +# +# /set nicklist_color <ON|OFF> +# * colourise the nicks in the nicklist (required nickcolor script +# with get_nick_color2 and debug_ansicolour functions) +# +# /set nicklist_gone_sort <ON|OFF> +# * sort away people below +# +# It supports mouse scrolling and the following keys: +# k/up arrow: up one line +# j/down arrow: down one line +# u/pageup: up 50% lines +# d/pagedown: down 50% lines +# gg: go to top +# G: go to bottom +# +# For better integration, unrecognized sequences will be sent to irssi and +# its pane will be focused. +# +# to toggle the nicklist if it is in the way you can make a key binding: +# /bind meta-Z /script exec Irssi::Script::tmux_nicklist_portable::toggle_nicklist +################################################################################ + +use strict; +use warnings; +use IO::Handle; +use IO::Select; +use POSIX; +use File::Temp qw/ :mktemp /; +use File::Basename; +our $VERSION = '0.1.8'; +our %IRSSI = ( + authors => 'Thiago de Arruda', + contact => 'tpadilha84@gmail.com', + name => 'tmux-nicklist', + description => 'displays a list of nicks in a separate tmux pane', + license => 'WTFPL', +); + +# "other" prefixes by danielg4 <daniel@gimpelevich.san-francisco.ca.us> +# added 'd' and 'u' navigation as in vim, by @gerardbm (github) + +{ package Irssi::Nick } + +if ($#ARGV == -1) { +require Irssi; + +my $enabled = 0; +my $nicklist_toggle = 1; +my $script_path = __FILE__; +my $tmpdir; +my $fifo_path; +my $fifo; +my $just_launched; +my $resize_timer; + +sub enable_nicklist { + return if ($enabled); + $tmpdir = mkdtemp Irssi::get_irssi_dir()."/nicklist-XXXXXXXX"; + $fifo_path = "$tmpdir/fifo"; + POSIX::mkfifo($fifo_path, 0600) or die "can't mkfifo $fifo_path: $!"; + my $cmd = "perl $script_path $fifo_path $ENV{TMUX_PANE}"; + my $width = Irssi::settings_get_int('nicklist_pane_width'); + system('tmux', 'split-window', '-dh', '-l', $width, '-t', $ENV{TMUX_PANE}, $cmd); + open_fifo(); + Irssi::timeout_remove($just_launched) if defined $just_launched; + $just_launched = Irssi::timeout_add_once(300, sub { $just_launched = undef; }, ''); +} + +sub open_fifo { + # The next system call will block until the other pane has opened the pipe + # for reading, so synchronization is not an issue here. + open $fifo, ">", $fifo_path or do { + if ($! == 4) { + Irssi::timeout_add_once(300, \&open_fifo, ''); + $enabled = -1 unless $enabled; + return; + } + die "can't open $fifo_path: $!"; + }; + $fifo->autoflush(1); + if ($enabled < -1) { + $enabled = 1; + disable_nicklist(); + } elsif ($enabled == -1) { + $enabled = 1; + reset_nicklist("enabled"); + } else { + $enabled = 1; + } +} + +sub disable_nicklist { + return unless ($enabled); + if ($enabled > 0) { + print $fifo "EXIT\n"; + close $fifo; + $fifo = undef; + unlink $fifo_path; + rmdir $tmpdir; + } + $enabled--; +} + +sub reset_nicklist { + my $event = shift; + my $active = Irssi::active_win(); + my $channel = $active->{active}; + return disable_nicklist unless $channel && ref $channel; + if ($event =~ /^nick/) { + # check if that nick event is for the current channel/nicklist + my ($event_channel) = @_; + return unless $channel->{_irssi} == $event_channel->{_irssi}; + } + my ($colourer, $ansifier); + if (Irssi::settings_get_bool('nicklist_color')) { + for my $script (sort map { my $z = $_; $z =~ s/::$//; $z } grep { /^nickcolor|nm/ } keys %Irssi::Script::) { + if ($colourer = "Irssi::Script::$script"->can('get_nick_color2')) { + $ansifier = "Irssi::Script::$script"->can('debug_ansicolour'); + last; + } + } + } + my $channel_pattern = Irssi::settings_get_str('nicklist_channel_re'); + { local $@; + $channel_pattern = eval { qr/$channel_pattern/ }; + $channel_pattern = qr/(?!)/ if $@; + } + my $smallest_main = Irssi::settings_get_int('nicklist_smallest_main'); + if (!$nicklist_toggle + || !$channel || !ref($channel) + || !$channel->isa('Irssi::Channel') + || !$channel->{'names_got'} + || $channel->{'name'} !~ $channel_pattern + || ($smallest_main && $channel->window->{width} < $smallest_main)) { + disable_nicklist; + } else { + my %colour; + my @nicks = $channel->nicks(); + my $max_nicks = Irssi::settings_get_int('nicklist_max_users'); + if ($max_nicks && @nicks > $max_nicks) { + disable_nicklist; + } else { + enable_nicklist; + return unless $enabled > 0; + foreach my $nick (sort { $a->{_irssi} <=> $b->{_irssi} } @nicks) { + $colour{$nick->{nick}} = ($ansifier && $colourer) ? $ansifier->($colourer->($active->{active}{server}{tag}, $channel->{name}, $nick->{nick}, 0)) : ''; + } + print($fifo "BEGIN\n"); + my $gone_sort = Irssi::settings_get_bool('nicklist_gone_sort'); + my $prefer_real; + if (exists $Irssi::Script::{'realnames::'}) { + my $code = "Irssi::Script::realnames"->can('use_realnames'); + $prefer_real = $code && $code->($channel); + } + my $_real = sub { + my $nick = shift; + $prefer_real && length $nick->{'realname'} ? $nick->{'realname'} : $nick->{'nick'} + }; + foreach my $nick (sort {($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':$a->{'other'}>32?'0':'4').($gone_sort?($a->{'gone'}?1:0):'').lc($_real->($a)) + cmp ($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':$b->{'other'}>32?'0':'4').($gone_sort?($b->{'gone'}?1:0):'').lc($_real->($b))} @nicks) { + my $colour = $colour{$nick->{nick}} || "\e[39m"; + $colour = "\e[37m" if $nick->{'gone'}; + print($fifo "NICK"); + if ($nick->{'op'}) { + print($fifo "\e[32m\@$colour".$_real->($nick)."\e[39m"); + } elsif ($nick->{'halfop'}) { + print($fifo "\e[34m%$colour".$_real->($nick)."\e[39m"); + } elsif ($nick->{'voice'}) { + print($fifo "\e[33m+$colour".$_real->($nick)."\e[39m"); + } elsif ($nick->{'other'}>32) { + print($fifo "\e[31m".(chr $nick->{'other'})."$colour".$_real->($nick)."\e[39m"); + } else { + print($fifo " $colour".$_real->($nick)."\e[39m"); + } + print($fifo "\n"); + } + print($fifo "END\n"); + } + } +} + +sub toggle_nicklist { + if ($enabled) { + $nicklist_toggle = undef + } else { + $nicklist_toggle = 1; + } + reset_nicklist("toggle"); +} + +sub switch_channel { + print $fifo "SWITCH_CHANNEL\n" if $fifo; + &reset_nicklist; +} + +sub resized_timed { + Irssi::timeout_remove($resize_timer) if defined $resize_timer; + return if defined $just_launched; + $resize_timer = Irssi::timeout_add_once(1100, \&resized, ''); + #resized(); +} +sub resized { + $resize_timer = undef; + return if defined $just_launched; + return unless $enabled >= 0; + disable_nicklist; + Irssi::timeout_add_once(200, sub{reset_nicklist("terminal resized")}, ''); +} +sub UNLOAD { + disable_nicklist; +} + +Irssi::settings_add_str('tmux_nicklist', 'nicklist_channel_re', '.*'); +Irssi::settings_add_int('tmux_nicklist', 'nicklist_max_users', 0); +Irssi::settings_add_int('tmux_nicklist', 'nicklist_smallest_main', 0); +Irssi::settings_add_int('tmux_nicklist', 'nicklist_pane_width', 13); +Irssi::settings_add_bool('tmux_nicklist', 'nicklist_color', 1); +Irssi::settings_add_bool('tmux_nicklist', 'nicklist_gone_sort', 0); +Irssi::signal_add_last('window item changed', sub{switch_channel("window item changed",@_)}); +Irssi::signal_add_last('window changed', sub{switch_channel("window changed",@_)}); +Irssi::signal_add_last('channel joined', sub{switch_channel("channel joined",@_)}); +Irssi::signal_add('nicklist new', sub{reset_nicklist("nicklist new",@_)}); +Irssi::signal_add('nicklist remove', sub{reset_nicklist("nicklist remove",@_)}); +Irssi::signal_add('nicklist changed', sub{reset_nicklist("nicklist changed",@_)}); +Irssi::signal_add_first('nick mode changed', sub{reset_nicklist("nick mode changed",@_)}); +Irssi::signal_add('gui exit', \&disable_nicklist); +Irssi::signal_add_last('terminal resized', \&resized_timed); + +} else { +my $fifo_path = $ARGV[0]; +my $irssi_pane = $ARGV[1]; +# array to store the current channel nicknames +my @nicknames = (); + +# helper functions for manipulating the terminal +# escape sequences taken from +# http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html +sub enable_mouse { print "\e[?1000h"; } +# recognized sequences +my $MOUSE_SCROLL_DOWN="\e[Ma"; +my $MOUSE_SCROLL_UP="\e[M`"; +my $ARROW_DOWN="\e[B"; +my $ARROW_UP="\e[A"; +my $DOWN="j"; +my $UP="k"; +my $PAGE_DOWN="\e[6~"; +my $PAGE_UP="\e[5~"; +my $PAGE_DOWN_D="d"; +my $PAGE_UP_U="u"; +my $GO_TOP="gg"; +my $GO_BOTTOM="G"; + +my $current_line = 0; +my $sequence = ''; +my ($rows, $cols); + +sub term_size { + split ' ', `stty size`; +} + +sub redraw { + my $last_nick_idx = @nicknames; + my $last_idx = $current_line + $rows; + # normalize last visible index + if ($last_idx > ($last_nick_idx)) { + $last_idx = $last_nick_idx; + } + # redraw visible nicks + for my $i (reverse 1..$rows) { + print "\e[$i;1H\e[K"; + my $idx = $current_line + $i - 1; + if ($idx < $last_idx) { + my $z = 0; my $col = $cols; + for (split /(\e\[(?:\d|;|:|\?|\s)*.)/, $nicknames[$idx]) { + if ($z ^= 1) { + print +(substr $_, 0, $col) if $col > 0; + $col -= length; + } else { + print + } + } + } + } +} + +sub move_down { + $sequence = ''; + my $count = int $_[0]; + my $nickcount = $#nicknames; + return if ($nickcount <= $rows); + if ($count == -1) { + $current_line = $nickcount - $rows + 1; + redraw; + return; + } + my $visible = $nickcount - $current_line - $count + 1; + if ($visible > $rows) { + $current_line += $count; + redraw; + } elsif (($visible + $count) > $rows) { + # scroll the maximum we can + $current_line = $nickcount - $rows + 1; + redraw; + } +} + +sub move_up { + $sequence = ''; + my $count = int $_[0]; + if ($count == -1) { + $current_line = 0; + redraw; + return; + } + return if ($current_line == 0); + $count = 1 if $count == 0; + $current_line -= $count; + $current_line = 0 if $current_line < 0; + redraw; +} + +$SIG{INT} = 'IGNORE'; + +STDOUT->autoflush(1); +# setup terminal so we can listen for individual key presses without echo +`stty -icanon -echo`; + +# open named pipe and setup the 'select' wrapper object for listening on both +# fds(fifo and sdtin) +open my $fifo, "<", $fifo_path or die "can't open $fifo_path: $!"; +my $select = IO::Select->new(); +my @ready; +$select->add($fifo); +$select->add(\*STDIN); + +enable_mouse; +system('tput', 'smcup'); +print "\e[?7l"; #system('tput', 'rmam'); +system('tput', 'civis'); +MAIN: { + while (@ready = $select->can_read) { + foreach my $fd (@ready) { + ($rows, $cols) = term_size; + if ($fd == $fifo) { + while (<$fifo>) { + my $line = $_; + if ($line =~ /^BEGIN/) { + @nicknames = (); + } elsif ($line =~ /^SWITCH_CHANNEL/) { + $current_line = 0; + } elsif ($line =~ /^NICK(.+)$/) { + push @nicknames, $1; + } elsif ($line =~ /^END$/) { + redraw; + last; + } elsif ($line =~ /^EXIT$/) { + last MAIN; + } + } + } else { + my $key = ''; + sysread(STDIN, $key, 1); + $sequence .= $key; + if ($MOUSE_SCROLL_DOWN =~ /^\Q$sequence\E/) { + if ($MOUSE_SCROLL_DOWN eq $sequence) { + move_down 3; + # mouse scroll has two more bytes that I dont use here + # so consume them now to avoid sending unwanted bytes to + # irssi + sysread(STDIN, $key, 2); + } + } elsif ($MOUSE_SCROLL_UP =~ /^\Q$sequence\E/) { + if ($MOUSE_SCROLL_UP eq $sequence) { + move_up 3; + sysread(STDIN, $key, 2); + } + } elsif ($ARROW_DOWN =~ /^\Q$sequence\E/) { + move_down 1 if ($ARROW_DOWN eq $sequence); + } elsif ($ARROW_UP =~ /^\Q$sequence\E/) { + move_up 1 if ($ARROW_UP eq $sequence); + } elsif ($DOWN =~ /^\Q$sequence\E/) { + move_down 1 if ($DOWN eq $sequence); + } elsif ($UP =~ /^\Q$sequence\E/) { + move_up 1 if ($UP eq $sequence); + } elsif ($PAGE_DOWN =~ /^\Q$sequence\E/) { + move_down $rows/2 if ($PAGE_DOWN eq $sequence); + } elsif ($PAGE_UP =~ /^\Q$sequence\E/) { + move_up $rows/2 if ($PAGE_UP eq $sequence); + } elsif ($PAGE_DOWN_D =~ /^\Q$sequence\E/) { + move_down $rows/2 if ($PAGE_DOWN_D eq $sequence); + } elsif ($PAGE_UP_U =~ /^\Q$sequence\E/) { + move_up $rows/2 if ($PAGE_UP_U eq $sequence); + } elsif ($GO_BOTTOM =~ /^\Q$sequence\E/) { + move_down -1 if ($GO_BOTTOM eq $sequence); + } elsif ($GO_TOP =~ /^\Q$sequence\E/) { + move_up -1 if ($GO_TOP eq $sequence); + } else { + # Unrecognized sequences will be send to irssi and its pane + # will be focused + system('tmux', 'send-keys', '-t', $irssi_pane, $sequence); + system('tmux', 'select-pane', '-t', $irssi_pane); + $sequence = ''; + } + } + } + } +} + +close $fifo; + +} diff --git a/.oh-my-zsh/custom/plugins/zsh-autocomplete b/.oh-my-zsh/custom/plugins/zsh-autocomplete new file mode 160000 +Subproject 20f6c34f20270084b21211428afb6d2534aae8e diff --git a/.oh-my-zsh/custom/plugins/zsh-autosuggestions b/.oh-my-zsh/custom/plugins/zsh-autosuggestions new file mode 160000 +Subproject 85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc diff --git a/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting b/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting new file mode 160000 +Subproject 1d85c692615a25fe2293bdd44b34c217d5d2bf0 diff --git a/.tmux.conf b/.tmux.conf new file mode 100644 index 0000000..aca9b74 --- /dev/null +++ b/.tmux.conf @@ -0,0 +1,22 @@ +set -g mouse on +set -g default-terminal "screen-256color" +set -g status-bg colour0 +set -g set-clipboard on +set -g @mighty-scroll-interval 3 +set -g @mighty-scroll-by-line 'man fzf' +set -g @mighty-scroll-select-pane off +set-option -g status-position top +set-option -g status-right-length 150 + +# plugins +set -g @plugin 'tmux-plugins/tpm' +set -g @plugin 'tmux-plugins/tmux-sensible' +set -g @plugin 'noscript/tmux-mighty-scroll' +set -g @plugin 'tmux-plugins/tmux-resurrect' +set -g @plugin 'tmux-plugins/tmux-continuum' +set -g @plugin 'tmux-plugins/tmux-logging' +set -g @plugin 'erikw/tmux-powerline' +set-option -g @plugin 'b0o/tmux-autoreload' + +set-option -g @tmux-autoreload-configs '~/.tmux.conf' +run '~/.tmux/plugins/tpm/tpm' diff --git a/.tmux/plugins/tmux-autoreload b/.tmux/plugins/tmux-autoreload new file mode 160000 +Subproject e98aa3b74cfd5f2df2be2b5d4aa4ddcc843b2eb diff --git a/.tmux/plugins/tmux-continuum b/.tmux/plugins/tmux-continuum new file mode 160000 +Subproject 0698e8f4b17d6454c71bf5212895ec055c578da diff --git a/.tmux/plugins/tmux-logging b/.tmux/plugins/tmux-logging new file mode 160000 +Subproject b5c5f7b9bc679ca161a442e932d6186da8d3538 diff --git a/.tmux/plugins/tmux-mighty-scroll b/.tmux/plugins/tmux-mighty-scroll new file mode 160000 +Subproject fa5db0718e9e9f7278520ecf63b96b84b0cc57d diff --git a/.tmux/plugins/tmux-powerline b/.tmux/plugins/tmux-powerline new file mode 160000 +Subproject d70011158dc389070d6ed7a67b65367206b6dde diff --git a/.tmux/plugins/tmux-resurrect b/.tmux/plugins/tmux-resurrect new file mode 160000 +Subproject cff343cf9e81983d3da0c8562b01616f12e8d54 diff --git a/.tmux/plugins/tmux-sensible b/.tmux/plugins/tmux-sensible new file mode 160000 +Subproject 25cb91f42d020f675bb0a2ce3fbd3a5d96119ef diff --git a/.tmux/plugins/tpm b/.tmux/plugins/tpm new file mode 160000 +Subproject 99469c4a9b1ccf77fade25842dc7bafbc8ce994 @@ -0,0 +1,117 @@ +# If you come from bash you might have to change your $PATH. +# export PATH=$HOME/bin:/usr/local/bin:$PATH + +# Path to your oh-my-zsh installation. +export ZSH="$HOME/.oh-my-zsh" + +# Set name of the theme to load --- if set to "random", it will +# load a random theme each time oh-my-zsh is loaded, in which case, +# to know which specific one was loaded, run: echo $RANDOM_THEME +# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes +ZSH_THEME="agnoster" + +# Set list of themes to pick from when loading at random +# Setting this variable when ZSH_THEME=random will cause zsh to load +# a theme from this variable instead of looking in $ZSH/themes/ +# If set to an empty array, this variable will have no effect. +# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" ) + +# Uncomment the following line to use case-sensitive completion. +# CASE_SENSITIVE="true" + +# Uncomment the following line to use hyphen-insensitive completion. +# Case-sensitive completion must be off. _ and - will be interchangeable. +# HYPHEN_INSENSITIVE="true" + +# Uncomment one of the following lines to change the auto-update behavior +# zstyle ':omz:update' mode disabled # disable automatic updates +# zstyle ':omz:update' mode auto # update automatically without asking +# zstyle ':omz:update' mode reminder # just remind me to update when it's time + +# Uncomment the following line to change how often to auto-update (in days). +# zstyle ':omz:update' frequency 13 + +# Uncomment the following line if pasting URLs and other text is messed up. +DISABLE_MAGIC_FUNCTIONS="true" + +# Uncomment the following line to disable colors in ls. +# DISABLE_LS_COLORS="true" + +# Uncomment the following line to disable auto-setting terminal title. +DISABLE_AUTO_TITLE="true" + +# Uncomment the following line to enable command auto-correction. +# ENABLE_CORRECTION="true" + +# Uncomment the following line to display red dots whilst waiting for completion. +# You can also set it to another string to have that shown instead of the default red dots. +# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f" +# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765) +# COMPLETION_WAITING_DOTS="true" + +# Uncomment the following line if you want to disable marking untracked files +# under VCS as dirty. This makes repository status check for large repositories +# much, much faster. +# DISABLE_UNTRACKED_FILES_DIRTY="true" + +# Uncomment the following line if you want to change the command execution time +# stamp shown in the history command output. +# You can set one of the optional three formats: +# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" +# or set a custom format using the strftime function format specifications, +# see 'man strftime' for details. +# HIST_STAMPS="mm/dd/yyyy" + +# Would you like to use another custom folder than $ZSH/custom? +# ZSH_CUSTOM=/path/to/new-custom-folder + +# Which plugins would you like to load? +# Standard plugins can be found in $ZSH/plugins/ +# Custom plugins may be added to $ZSH_CUSTOM/plugins/ +# Example format: plugins=(rails git textmate ruby lighthouse) +# Add wisely, as too many plugins slow down shell startup. +plugins=(git brew zsh-autosuggestions zsh-syntax-highlighting zsh-autocomplete colored-man-pages command-not-found safe-paste colorize taskwarrior) + +source $ZSH/oh-my-zsh.sh + +# User configuration + +# export MANPATH="/usr/local/man:$MANPATH" + +# You may need to manually set your language environment +# export LANG=en_US.UTF-8 + +# Preferred editor for local and remote sessions +# if [[ -n $SSH_CONNECTION ]]; then +# export EDITOR='vim' +# else +# export EDITOR='nvim' +# fi + +# Compilation flags +# export ARCHFLAGS="-arch x86_64" + +# Set personal aliases, overriding those provided by oh-my-zsh libs, +# plugins, and themes. Aliases can be placed here, though oh-my-zsh +# users are encouraged to define aliases within the ZSH_CUSTOM folder. +# For a full list of active aliases, run `alias`. +# +# Example aliases +# alias zshconfig="mate ~/.zshrc" +# alias ohmyzsh="mate ~/.oh-my-zsh" + +export PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/.local/bin + +alias vim="nvim" +alias cat="ccat" + +prompt_context(){} +export PATH="/opt/homebrew/sbin:$PATH" +export JAVA_HOME="/opt/homebrew/opt/openjdk" +export PATH="$JAVA_HOME/bin:$PATH" +export PATH="$HOME/Library/Python/3.14/bin:$PATH" +export HOMEBREW_NO_UPDATE_REPORT_NEW=1 + + +test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh" || true + diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000..6d4ef56 --- /dev/null +++ b/Brewfile @@ -0,0 +1,130 @@ +brew "openssl@3" +brew "tree" +brew "ansible" +brew "ansible-lint" +brew "ansifilter" +brew "calc" +brew "tree-sitter" +brew "cask" +brew "chroma" +brew "cpanminus" +brew "docker" +brew "dos2unix" +brew "entr" +brew "exif" +brew "fd" +brew "feh" +brew "ffmpeg" +brew "fzf" +brew "yt-dlp" +brew "gallery-dl" +brew "openjpeg" +brew "ghostscript" +brew "git" +brew "git-lfs" +brew "go" +brew "gobuster" +brew "openjdk" +brew "groovy" +brew "handbrake", link: false +brew "hashcat" +brew "ncurses" +brew "htop" +brew "hydra" +brew "imagemagick" +brew "iperf3" +brew "irssi" +brew "john" +brew "lazygit" +brew "mas" +brew "masscan" +brew "mkvtoolnix" +brew "mpv" +brew "mupdf-tools" +brew "ncdu" +brew "neovim" +brew "nikto" +brew "nmap" +brew "node" +brew "pandoc" +brew "perl" +brew "powershell", link: false +brew "pwncat" +brew "python@3.12" +brew "python@3.13" +brew "rclone" +brew "ripgrep" +brew "ripgrep-all" +brew "rsync" +brew "rust" +brew "sevenzip" +brew "shellcheck" +brew "shfmt" +brew "task" +brew "taskwarrior-tui" +brew "testdisk" +brew "theharvester" +brew "tmux" +brew "unum" +brew "uv" +brew "watch" +brew "web-ext" +brew "wget" +brew "wireshark" +brew "zsh" +cask "angry-ip-scanner" +cask "balenaetcher" +cask "betterdisplay" +cask "caffeine" +cask "cursor" +cask "db-browser-for-sqlite" +cask "dbeaver-community" +cask "docker-desktop" +cask "drawio" +cask "firefox" +cask "font-hack-nerd-font" +cask "gimp" +cask "google-chrome" +cask "handbrake-app" +cask "hex-fiend" +cask "iina" +cask "iterm2" +cask "jump-desktop" +cask "libreoffice" +cask "makemkv" +cask "mediainfo" +cask "obsidian" +cask "openvpn-connect" +cask "powershell" +cask "rapidapi" +cask "spotify" +cask "stats" +cask "sublime-text" +mas "Apple Configurator", id: 1037126344 +mas "DaVinci Resolve", id: 571213070 +vscode "ahmadawais.shades-of-purple" +vscode "davidanson.vscode-markdownlint" +vscode "enkia.tokyo-night" +vscode "foxundermoon.shell-format" +vscode "gitlab.gitlab-workflow" +vscode "kevinrose.vsc-python-indent" +vscode "ms-python.debugpy" +vscode "ms-python.python" +vscode "ms-python.vscode-pylance" +vscode "ms-python.vscode-python-envs" +vscode "ms-toolsai.jupyter" +vscode "ms-toolsai.jupyter-keymap" +vscode "ms-toolsai.jupyter-renderers" +vscode "ms-toolsai.vscode-jupyter-cell-tags" +vscode "ms-toolsai.vscode-jupyter-slideshow" +vscode "ms-vscode.live-server" +vscode "ms-vscode.powershell" +vscode "ms-vscode.remote-explorer" +vscode "ms-vscode.remote-server" +vscode "ms-vsliveshare.vsliveshare" +vscode "redhat.ansible" +vscode "redhat.vscode-xml" +vscode "redhat.vscode-yaml" +vscode "sidthesloth.html5-boilerplate" +vscode "yzhang.markdown-all-in-one" +uv "ansible-dev-environment" diff --git a/README.md b/README.md new file mode 100644 index 0000000..f043054 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Mac Dotfiles + +Dotfiles for MacOS + +## Installation + +```bash +chmod +x ./scripts/*.sh +./scripts/setup-mac.sh +./scripts/omz.sh +./scripts/brew.sh +mkdir -p ~/.tmux/plugins +git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm +cp .tmux.conf ~/.tmux.conf +~/.tmux/plugins/tpm/bin/install_plugins +``` + +## MacOS System Preferences (setup-mac.sh) + +- Dock on the left with autohide +- Screenshots save to Downloads folder +- Hidden desktop items +- Finder with path bar and folder then file A-Z sorting +- Fast keyboard repeat + +## Dynamic iTerm2 colours depending on wallpaper via wal-item.py script + +```bash +cd iTerm +python3 -m venv .venv +source .venv/bin/activate +python3 -m pip install pywal16 haishoku +python3 wal-iterm.py ~/path/to/wallpaper.png +``` + +If you dont see any change make sure your default profile is set to wal diff --git a/iTerm/DynamicProfiles/wal-profile.json b/iTerm/DynamicProfiles/wal-profile.json new file mode 100644 index 0000000..6f625aa --- /dev/null +++ b/iTerm/DynamicProfiles/wal-profile.json @@ -0,0 +1,10 @@ +{ + "Profiles" : [ + { + "Use Separate Colors for Light and Dark Mode" : false, + "Name" : "wal", + "Rewritable" : true, + "Guid" : "wal-dynamic-profile-uuid" + } + ] +}
\ No newline at end of file diff --git a/iTerm/wal-iterm.py b/iTerm/wal-iterm.py new file mode 100644 index 0000000..6e9b443 --- /dev/null +++ b/iTerm/wal-iterm.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +""" +Script to run pywal and apply colors to iTerm2 automatically. +Usage: python3 wal-iterm.py [path_to_image] +""" + +import subprocess +import sys +import os +import json +import tempfile +from pathlib import Path +import plistlib + +HOME = Path.home() +WAL_CACHE = HOME / ".cache" / "wal" +ITERM_COLORS_DIR = WAL_CACHE / "itermcolors" +COLORS_JSON = WAL_CACHE / "colors.json" + + +def run_command(cmd, check=True): + """Run a shell command and return the result.""" + try: + result = subprocess.run( + cmd, shell=True, capture_output=True, text=True, check=check + ) + return result.stdout.strip(), result.stderr.strip(), result.returncode + except subprocess.CalledProcessError as e: + print(f"Error running command: {cmd}") + print(f"Error: {e.stderr}") + sys.exit(1) + + +def hex_to_rgb(hex_color): + """Convert hex color to RGB values (0-1 range).""" + hex_color = hex_color.lstrip('#') + r = int(hex_color[0:2], 16) / 255.0 + g = int(hex_color[2:4], 16) / 255.0 + b = int(hex_color[4:6], 16) / 255.0 + return r, g, b + + +def run_wal(image_path=None, backend="haishoku"): + """Run pywal to generate colors.""" + if image_path: + if not os.path.exists(image_path): + print(f"Error: Image file not found: {image_path}") + sys.exit(1) + print(f"Running wal on image: {image_path} (backend: {backend})") + cmd = f'wal -i "{image_path}" --backend {backend}' + else: + print("Running wal to regenerate colors from last image...") + cmd = "wal -n" + + stdout, stderr, returncode = run_command(cmd, check=False) + + if returncode != 0: + print(f"\nError: wal failed to process the image.") + if stderr: + print(f"Details: {stderr}") + + if not image_path: + print("Cannot retry without image path. Please specify an image.") + sys.exit(1) + + # Try alternative backends as fallback + fallback_backends = ["colorthief", "colorz", "wal"] + + for fallback_backend in fallback_backends: + if fallback_backend == backend: + continue + print(f"\nTrying with {fallback_backend} backend...") + cmd_fallback = f'wal -i "{image_path}" --backend {fallback_backend}' + stdout, stderr, returncode = run_command(cmd_fallback, check=False) + + if returncode == 0: + print(f"✓ Successfully generated colors using {fallback_backend} backend") + break + else: + print(f" {fallback_backend} backend also failed") + else: + print(f"\nError: wal failed with all attempted backends.") + print("This may be a pywal bug with this specific image.") + print("Suggestions:") + print(" - Try a different image") + print(" - Update pywal: pip install --upgrade pywal") + print(" - Try manually: wal -i <image> --backend <backend>") + sys.exit(1) + + if stderr and "error" not in stderr.lower(): + print(stderr) + + print("✓ Colors generated by wal") + + + + + +def create_dynamic_profile(): + """Create/update a dynamic profile with pywal colors.""" + print("Creating/updating dynamic profile...") + + if not COLORS_JSON.exists(): + print(f"Error: colors.json not found at {COLORS_JSON}") + sys.exit(1) + + # Read pywal colors + with open(COLORS_JSON) as f: + colors = json.load(f) + + colors_dict = colors.get("colors", {}) + special = colors.get("special", {}) + + # Create dynamic profile structure + dynamic_profile = { + "Profiles": [ + { + "Name": "wal", + "Guid": "wal-dynamic-profile-uuid", + "Rewritable": True, + } + ] + } + + profile = dynamic_profile["Profiles"][0] + + # Add ANSI colors (0-15) + for i in range(16): + color_key = f"color{i}" + hex_color = colors_dict.get(color_key, "#000000") + r, g, b = hex_to_rgb(hex_color) + profile[f"Ansi {i} Color"] = { + "Color Space": "sRGB", + "Red Component": r, + "Green Component": g, + "Blue Component": b, + "Alpha Component": 1.0, + } + + # Add special colors + profile["Background Color"] = { + "Color Space": "sRGB", + "Red Component": hex_to_rgb(special.get("background", "#000000"))[0], + "Green Component": hex_to_rgb(special.get("background", "#000000"))[1], + "Blue Component": hex_to_rgb(special.get("background", "#000000"))[2], + "Alpha Component": 1.0, + } + + profile["Foreground Color"] = { + "Color Space": "sRGB", + "Red Component": hex_to_rgb(special.get("foreground", "#ffffff"))[0], + "Green Component": hex_to_rgb(special.get("foreground", "#ffffff"))[1], + "Blue Component": hex_to_rgb(special.get("foreground", "#ffffff"))[2], + "Alpha Component": 1.0, + } + + profile["Cursor Color"] = { + "Color Space": "sRGB", + "Red Component": hex_to_rgb(special.get("cursor", "#ffffff"))[0], + "Green Component": hex_to_rgb(special.get("cursor", "#ffffff"))[1], + "Blue Component": hex_to_rgb(special.get("cursor", "#ffffff"))[2], + "Alpha Component": 1.0, + } + + # Write the dynamic profile + dynamic_profiles_dir = Path.home() / "Library/Application Support/iTerm2/DynamicProfiles" + dynamic_profiles_dir.mkdir(parents=True, exist_ok=True) + profile_file = dynamic_profiles_dir / "wal-profile.json" + + with open(profile_file, 'w') as f: + json.dump(dynamic_profile, f, indent=2) + + print(f"✓ Dynamic profile created/updated: {profile_file}") + print("✓ iTerm2 will automatically detect the changes") + print("\nTo use: Switch to the 'wal' profile in iTerm2") + print("Future runs will update the 'wal' profile automatically") + + +def main(): + """Main function.""" + image_path = sys.argv[1] if len(sys.argv) > 1 else None + + run_wal(image_path, backend="haishoku") + create_dynamic_profile() + + print("\n✓ Done! Dynamic profile 'wal' updated with new colors.") + + +if __name__ == "__main__": + main() + diff --git a/scripts/brew.sh b/scripts/brew.sh new file mode 100755 index 0000000..7ae70d1 --- /dev/null +++ b/scripts/brew.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env zsh +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +BREWFILE_PATH="$REPO_ROOT/Brewfile" + +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +brew bundle --file "$BREWFILE_PATH"
\ No newline at end of file diff --git a/scripts/omz.sh b/scripts/omz.sh new file mode 100755 index 0000000..7dd94c3 --- /dev/null +++ b/scripts/omz.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env zsh +# Install OMZ +set -e +sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" + +# Powerline fonts +mkdir -p /tmp/fonts/ +git clone https://github.com/powerline/fonts.git --depth=1 /tmp/fonts/ +chmod +x /tmp/fonts/install.sh +bash /tmp/fonts/install.sh +rm -rf /tmp/fonts/ + +sleep 2s + +# Install plugins +git clone --depth 1 -- https://github.com/zsh-users/zsh-autosuggestions.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions +git clone --depth 1 -- https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting +git clone --depth 1 -- https://github.com/marlonrichert/zsh-autocomplete.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autocomplete + +# Overwrite zshrc +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cp "$REPO_ROOT/.zshrc" "$HOME/.zshrc"
\ No newline at end of file diff --git a/scripts/setup-mac.sh b/scripts/setup-mac.sh new file mode 100755 index 0000000..3c16987 --- /dev/null +++ b/scripts/setup-mac.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env zsh +# Dock on left +defaults write com.apple.dock "orientation" -string "left" && killall Dock +sleep 0.25s + +# Set dock icon size +defaults write com.apple.dock "tilesize" -int "25" && killall Dock +sleep 0.25s + +# Autohide dock +defaults write com.apple.dock "autohide" -bool "true" && killall Dock +sleep 0.25s + +# Dont show recent apps +defaults write com.apple.dock "show-recents" -bool "false" && killall Dock +sleep 0.25s + +# Set min animation to scale +defaults write com.apple.dock "mineffect" -string "scale" && killall Dock +sleep 0.25s + +# Set dock magnification +defaults write com.apple.dock magnification -bool "true" +defaults write com.apple.dock largesize -int "48" +killall Dock + +# Save screenshots to downloads +defaults write com.apple.screencapture "location" -string "~/Downloads" && killall SystemUIServer +sleep 0.25s + +# Set Clock +defaults write com.apple.menuextra.clock "DateFormat" -string "\"EEE d MMM HH:mm:ss\"" +sleep 0.25s + +# Disable the .DS file creation on USB and Network +defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true +defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true +sleep 0.25s + +# Hide desktop items and Show the path bar in the Finder +defaults write com.apple.finder "CreateDesktop" -bool "false" +defaults write com.apple.finder "ShowPathbar" -bool "true" && killall Finder +sleep 0.25s + +# Show hidden files in the Finder +defaults write com.apple.finder "AppleShowAllFiles" -bool "false" && killall Finder +sleep 0.25s + +# Keep folders on top in Finder +defaults write com.apple.finder "_FXSortFoldersFirst" -bool "true" && killall Finder +sleep 0.25s + +# Set Key repeat speed +defaults read NSGlobalDomain InitialKeyRepeat -int 15 +defaults read NSGlobalDomain KeyRepeat -int 2 +sleep 0.25s + +# Disable click wallpaper +defaults write com.apple.WindowManager EnableStandardClickToShowDesktop -bool false +killall WindowManager + +# Apply the settings +/System/Library/PrivateFrameworks/SystemAdministration.framework/Resources/activateSettings -u +sleep 2s
\ No newline at end of file diff --git a/terminal-profiles/Afterglow.terminal b/terminal-profiles/Afterglow.terminal new file mode 100644 index 0000000..f07ae81 --- /dev/null +++ b/terminal-profiles/Afterglow.terminal @@ -0,0 +1,222 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>ANSIBlackColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAqMC4wODIzNTI5NDM3MiAwLjA4MjM1Mjk0 + MzcyIDAuMDgyMzUyOTQzNzIAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlND + b2xvcqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+q62vtL/I0NMAAAAAAAABAQAA + AAAAAAAZAAAAAAAAAAAAAAAAAAAA3A== + </data> + <key>ANSIBlueColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAeMC40MjM1Mjk0MTE4IDAuNiAwLjczMzMz + MzMzMzMAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqIWGFhOU09i + amVjdAgRGiQpMjdJTFFTV11kand+n6GjqLO8xMcAAAAAAAABAQAAAAAAAAAZAAAAAAAA + AAAAAAAAAAAA0A== + </data> + <key>ANSIBrightBlackColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4zMTM3MjU1MDEzIDAuMzEzNzI1NTAx + MyAwLjMxMzcyNTUwMTMAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightBlueColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAeMC40MjM1Mjk0MTE4IDAuNiAwLjczMzMz + MzMzMzMAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqIWGFhOU09i + amVjdAgRGiQpMjdJTFFTV11kand+n6GjqLO8xMcAAAAAAAABAQAAAAAAAAAZAAAAAAAA + AAAAAAAAAAAA0A== + </data> + <key>ANSIBrightCyanColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40OTAzMTg3OTk5IDAuODM4NTMyMTYy + NCAwLjgxMTgxNTE5OTEAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightGreenColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40OTQ3MzgwNDM5IDAuNTU1NzY1Njk1 + NyAwLjMxNDQ0NjY2NzUAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightMagentaColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42MjMzMzg1MTgxIDAuMzA2OTc3OTg1 + OCAwLjUyMzQ0NjY5ODEAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightRedColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NzQ1MDk4MjMzIDAuMjU0OTAxOTc1 + NCAwLjI1ODgyMzU0MzgAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightWhiteColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC45NjA3ODQzMTYxIDAuOTYwNzg0MzE2 + MSAwLjk2MDc4NDMxNjEAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightYellowColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44OTgwMzkyMTU3IDAuNzA5ODAzOTIx + NiAwLjQwMzkyMTU2ODYAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSICyanColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40OTAzMTg3OTk5IDAuODM4NTMyMTYy + NCAwLjgxMTgxNTE5OTEAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIGreenColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40OTQ3MzgwNDM5IDAuNTU1NzY1Njk1 + NyAwLjMxNDQ0NjY2NzUAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIMagentaColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42MjMzMzg1MTgxIDAuMzA2OTc3OTg1 + OCAwLjUyMzQ0NjY5ODEAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIRedColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NzQ1MDk4MjMzIDAuMjU0OTAxOTc1 + NCAwLjI1ODgyMzU0MzgAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIWhiteColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTU2ODYyODU1IDAuODE1Njg2Mjg1 + NSAwLjgxNTY4NjI4NTUAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIYellowColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44OTgwMzkyMTU3IDAuNzA5ODAzOTIx + NiAwLjQwMzkyMTU2ODYAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>BackgroundColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4xMjgzNDA2MzkxIDAuMTI4MzQwNjM5 + MSAwLjEyODM0MDYzOTEAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>Bell</key> + <false/> + <key>CursorColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTU2ODYyODU1IDAuODE1Njg2Mjg1 + NSAwLjgxNTY4NjI4NTUAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>Font</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwVFlUkbnVsbNQNDg8QERIT + FFZOU1NpemVYTlNmRmxhZ3NWTlNOYW1lViRjbGFzcyNAJgAAAAAAABAQgAKAA1xIYWNr + LVJlZ3VsYXLSFxgZGlokY2xhc3NuYW1lWCRjbGFzc2VzVk5TRm9udKIZG1hOU09iamVj + dAgRGiQpMjdJTFFTWF5nbnd+hY6QkpShprG6wcQAAAAAAAABAQAAAAAAAAAcAAAAAAAA + AAAAAAAAAAAAzQ== + </data> + <key>FontAntialias</key> + <true/> + <key>ProfileCurrentVersion</key> + <real>2.0699999999999998</real> + <key>SelectionColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4xODgyMzUyOTc4IDAuMTg4MjM1Mjk3 + OCAwLjE4ODIzNTI5NzgAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>TextBoldColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTU2ODYyODU1IDAuODE1Njg2Mjg1 + NSAwLjgxNTY4NjI4NTUAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>TextColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTU2ODYyODU1IDAuODE1Njg2Mjg1 + NSAwLjgxNTY4NjI4NTUAEAKAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>VisualBell</key> + <false/> + <key>columnCount</key> + <integer>140</integer> + <key>name</key> + <string>Afterglow</string> + <key>rowCount</key> + <integer>35</integer> + <key>type</key> + <string>Window Settings</string> + <key>useOptionAsMetaKey</key> + <true/> +</dict> +</plist> diff --git a/terminal-profiles/Nord.terminal b/terminal-profiles/Nord.terminal new file mode 100644 index 0000000..4794f97 --- /dev/null +++ b/terminal-profiles/Nord.terminal @@ -0,0 +1,295 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>ANSIBlackColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4xNzY0NzA1ODgyIDAuMTk2MDc4NDMx + NCAwLjI1NDkwMTk2MDgAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBlueColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40Mjc0NTA5ODA0IDAuNTU2ODYyNzQ1 + MSAwLjcwOTgwMzkyMTYAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightBlackColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAlMC4yMzEzNzI1NDkgMC4yNjI3NDUwOTgg + MC4zNDUwOTgwMzkyABABgALSFBUWF1okY2xhc3NuYW1lWCRjbGFzc2VzV05TQ29sb3Ki + FhhYTlNPYmplY3QIERokKTI3SUxRU1ddZGp3fqaoqq+6w8vOAAAAAAAAAQEAAAAAAAAA + GQAAAAAAAAAAAAAAAAAAANc= + </data> + <key>ANSIBrightBlueColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40Mjc0NTA5ODA0IDAuNTU2ODYyNzQ1 + MSAwLjcwOTgwMzkyMTYAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightCyanColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40ODYyNzQ1MDk4IDAuNjg2Mjc0NTA5 + OCAwLjY3ODQzMTM3MjUAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightGreenColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC41NzI1NDkwMTk2IDAuNzA1ODgyMzUy + OSAwLjQ2NjY2NjY2NjcAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightMagentaColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NDcwNTg4MjM1IDAuNDcwNTg4MjM1 + MyAwLjYxOTYwNzg0MzEAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightRedColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAmMC42OTQxMTc2NDcxIDAuMjkwMTk2MDc4 + NCAwLjMzNzI1NDkwMgAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9y + ohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRqd36nqauwu8TMzwAAAAAAAAEBAAAAAAAA + ABkAAAAAAAAAAAAAAAAAAADY + </data> + <key>ANSIBrightWhiteColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC45MDU4ODIzNTI5IDAuOTIxNTY4NjI3 + NSAwLjk0NTA5ODAzOTIAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIBrightYellowColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC45MDE5NjA3ODQzIDAuNzYwNzg0MzEz + NyAwLjQ1NDkwMTk2MDgAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSICyanColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC40NTg4MjM1Mjk0IDAuNzAxOTYwNzg0 + MyAwLjc4MDM5MjE1NjkAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIGreenColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC41NzI1NDkwMTk2IDAuNzA1ODgyMzUy + OSAwLjQ2NjY2NjY2NjcAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIMagentaColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NDcwNTg4MjM1IDAuNDcwNTg4MjM1 + MyAwLjYxOTYwNzg0MzEAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIRedColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAmMC42OTQxMTc2NDcxIDAuMjkwMTk2MDc4 + NCAwLjMzNzI1NDkwMgAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9y + ohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRqd36nqauwu8TMzwAAAAAAAAEBAAAAAAAA + ABkAAAAAAAAAAAAAAAAAAADY + </data> + <key>ANSIWhiteColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44NzQ1MDk4MDM5IDAuODkwMTk2MDc4 + NCAwLjkyOTQxMTc2NDcAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>ANSIYellowColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC45MDE5NjA3ODQzIDAuNzYwNzg0MzEz + NyAwLjQ1NDkwMTk2MDgAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>BackgroundBlur</key> + <real>0.0</real> + <key>BackgroundBlurInactive</key> + <real>0.35006322552358482</real> + <key>BackgroundColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGmCwwXHR4lVSRudWxs1Q0ODxAR + EhMUFRZcTlNDb21wb25lbnRzVU5TUkdCXE5TQ29sb3JTcGFjZV8QEk5TQ3VzdG9tQ29s + b3JTcGFjZVYkY2xhc3NPECgwLjE2Mjg5MjI1MjIgMC4xOTA5MzUyNTQxIDAuMjEyMzE0 + NDI2OSAxTxAnMC4xMjI2MTI5NjgxIDAuMTQzMjY2NzY3MyAwLjE2MDI1MTAwNjUAEAGA + AoAF0xgZERobHFROU0lEVU5TSUNDEAeAA4AETxEMSAAADEhMaW5vAhAAAG1udHJSR0Ig + WFlaIAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAAAAAAAAAAAAD2 + 1gABAAAAANMtSFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAEWNwcnQAAAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAAFGJrcHQA + AAIEAAAAFHJYWVoAAAIYAAAAFGdYWVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJU + AAAAcGRtZGQAAALEAAAAiHZ1ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAA + FG1lYXMAAAQMAAAAJHRlY2gAAAQwAAAADHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJU + UkMAAAQ8AAAIDHRleHQAAAAAQ29weXJpZ2h0IChjKSAxOTk4IEhld2xldHQtUGFja2Fy + ZCBDb21wYW55AABkZXNjAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAA + EnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAAAAAAAAAAAAAA + AAAAAAAAWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAA + AAAAAAAkoAAAD4QAALbPZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAA + AAAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEg + RGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2MTk2 + Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAA + AAAAAAAAAABkZXNjAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4g + SUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9u + IGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdmlldwAAAAAA + E6T+ABRfLgAQzxQAA+3MAAQTCwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABXH+dtZWFz + AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAA + AAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABt + AHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA + 8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGS + AZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcC + cQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+ + A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE + 0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZ + BmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8I + MghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9 + ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4M + pwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9B + D14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYS + RRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4 + FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZ + IBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1 + HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwh + SCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXH + JfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsq + zysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+ + MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1 + wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuq + O+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5C + MEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjX + SR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91Q + J1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeS + V+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ff + s2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fp + aD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw + 4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnn + ekZ6pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eD + uoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Y + jf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CY + TJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMG + o3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2u + oa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7 + urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbG + w8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE + 08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4Dbg + veFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o + 7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8 + mP0p/br+S/7c/23//9IfICEiWiRjbGFzc25hbWVYJGNsYXNzZXNcTlNDb2xvclNwYWNl + oiMkXE5TQ29sb3JTcGFjZVhOU09iamVjdNIfICYnV05TQ29sb3KiJiQACAARABoAJAAp + ADIANwBJAEwAUQBTAFoAYABrAHgAfgCLAKAApwDSAPwA/gEAAQIBCQEOARQBFgEYARoN + Zg1rDXYNfw2MDY8NnA2lDaoNsgAAAAAAAAIBAAAAAAAAACgAAAAAAAAAAAAAAAAAAA21 + </data> + <key>BackgroundSettingsForInactiveWindows</key> + <true/> + <key>CursorBlink</key> + <true/> + <key>CursorColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTE3NjQ3MDU5IDAuODM5MjE1Njg2 + MyAwLjg5NDExNzY0NzEAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>CursorType</key> + <integer>2</integer> + <key>Font</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwVFlUkbnVsbNQNDg8QERIT + FFZOU1NpemVYTlNmRmxhZ3NWTlNOYW1lViRjbGFzcyNAJgAAAAAAABAQgAKAA1xIYWNr + LVJlZ3VsYXLSFxgZGlokY2xhc3NuYW1lWCRjbGFzc2VzVk5TRm9udKIZG1hOU09iamVj + dAgRGiQpMjdJTFFTWF5nbnd+hY6QkpShprG6wcQAAAAAAAABAQAAAAAAAAAcAAAAAAAA + AAAAAAAAAAAAzQ== + </data> + <key>FontAntialias</key> + <true/> + <key>ProfileCurrentVersion</key> + <real>2.0699999999999998</real> + <key>SelectionColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAeMC4yIDAuMjI3NDUwOTgwNCAwLjI5ODAz + OTIxNTcAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqIWGFhOU09i + amVjdAgRGiQpMjdJTFFTV11kand+n6GjqLO8xMcAAAAAAAABAQAAAAAAAAAZAAAAAAAA + AAAAAAAAAAAA0A== + </data> + <key>TextBoldColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTE3NjQ3MDU5IDAuODM5MjE1Njg2 + MyAwLjg5NDExNzY0NzEAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>TextColor</key> + <data> + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS + AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO + U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44MTE3NjQ3MDU5IDAuODM5MjE1Njg2 + MyAwLjg5NDExNzY0NzEAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv + cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA + AAAZAAAAAAAAAAAAAAAAAAAA2Q== + </data> + <key>UseBrightBold</key> + <false/> + <key>WindowTitle</key> + <string>Nord</string> + <key>columnCount</key> + <integer>140</integer> + <key>name</key> + <string>Nord</string> + <key>rowCount</key> + <integer>35</integer> + <key>type</key> + <string>Window Settings</string> +</dict> +</plist> |
