From: Samir Benmendil Date: Sun, 18 Jan 2015 23:44:19 +0000 (+0000) Subject: Merge branch 'master' of tardis:/dotfiles X-Git-Url: https://git.rmz.io/dotfiles.git/commitdiff_plain/f6e1ac53f8be388dc4c73117f0e3f96e005d6545?hp=2dd07dc82aa122e1ef8ccb6881437b1bd27b7608 Merge branch 'master' of tardis:/dotfiles --- diff --git a/awesome/bindings.lua b/awesome/bindings.lua index af2426e..5ff504e 100644 --- a/awesome/bindings.lua +++ b/awesome/bindings.lua @@ -70,8 +70,8 @@ globalkeys = awful.util.table.join(globalkeys, -- Prompt awful.key({ modkey }, "space", function () mypromptbox[mouse.screen]:run() end), -- switch layout - awful.key({ modkey }, "]", function () awful.layout.inc(layouts, 1) end), - awful.key({ modkey }, "[", function () awful.layout.inc(layouts, -1) end), + awful.key({ modkey }, "]", function () awful.layout.inc( 1, mouse.screen, layouts) end), + awful.key({ modkey }, "[", function () awful.layout.inc(-1, mouse.screen, layouts) end), -- resize slave awful.key({ modkey, "Control" }, "j", function () awful.client.incwfact( 0.05) end), awful.key({ modkey, "Control" }, "k", function () awful.client.incwfact(-0.05) end), diff --git a/dwb/forms b/dwb/forms index 71841a5..14baaba 100644 Binary files a/dwb/forms and b/dwb/forms differ diff --git a/mpv/config b/mpv/config index 3c5e101..025f82b 100644 --- a/mpv/config +++ b/mpv/config @@ -3,6 +3,7 @@ ytdl cache=auto cache-default=50000 cache-initial=100 +no-sub # profiles [mimeo] diff --git a/qutebrowser/keys.conf b/qutebrowser/keys.conf new file mode 100644 index 0000000..4b7e613 --- /dev/null +++ b/qutebrowser/keys.conf @@ -0,0 +1,476 @@ +# vim: ft=conf +# +# In this config file, qutebrowser's keybindings are configured. +# The format looks like this: +# +# [keymode] +# +# command +# keychain +# keychain2 +# ... +# +# All blank lines and lines starting with '#' are ignored. +# Inline-comments are not permitted. +# +# keymode is a comma separated list of modes in which the keybinding should be +# active. If keymode starts with !, the keybinding is active in all modes +# except the listed modes. +# +# For special keys (can't be part of a keychain), enclose them in `<`...`>`. +# For modifiers, you can use either `-` or `+` as delimiters, and these names: +# +# * Control: `Control`, `Ctrl` +# * Meta: `Meta`, `Windows`, `Mod4` +# * Alt: `Alt`, `Mod1` +# * Shift: `Shift` +# +# For simple keys (no `<>`-signs), a capital letter means the key is pressed +# with Shift. For special keys (with `<>`-signs), you need to explicitely add +# `Shift-` to match a key pressed with shift. You can bind multiple commands +# by separating them with `;;`. + +[!normal] + +leave-mode + + + +[normal] +# Keybindings for normal mode. + +set-cmd-text ":open " + o + +set-cmd-text ":open {url}" + go + +set-cmd-text ":open -t " + O + +set-cmd-text ":open -t {url}" + gO + +set-cmd-text ":open -b " + xo + +set-cmd-text ":open -b {url}" + xO + +set-cmd-text ":open -w " + wo + +set-cmd-text ":open -w {url}" + wO + +open -t about:blank + + +tab-close + d + + +tab-close -o + D + +tab-focus + T + +tab-move + gm + +tab-move - + gj + +tab-move + + gk + +tab-next + K + gt + +tab-prev + J + gT + +tab-clone + gC + +reload + r + +reload -f + R + +back + H + + +back -t + th + +back -w + wh + +forward + L + +forward -t + tl + +forward -w + wl + +fullscreen + + +hint + f + +hint all tab + F + +hint all window + wf + +hint all tab-bg + ;b + +hint all hover + ;h + +hint images + ;i + +hint images tab + ;I + +hint images tab-bg + .i + +hint links fill ":open {hint-url}" + ;o + +hint links fill ":open -t {hint-url}" + ;O + +hint links fill ":open -b {hint-url}" + .o + +hint links yank + ;y + +hint links yank-primary + ;Y + +hint links rapid + ;r + +hint links rapid-win + ;R + +hint links download + ;d + +scroll -50 0 + h + +scroll 0 50 + j + +scroll 0 -50 + k + +scroll 50 0 + l + +undo + u + + +scroll-perc 0 + gg + +scroll-perc + G + +search-next + n + +search-prev + N + +enter-mode insert + i + +yank + yy + +yank -s + yY + +yank -t + yt + +yank -ts + yT + +paste + pp + +paste -s + pP + +paste -t + Pp + +paste -ts + PP + +paste -w + wp + +paste -ws + wP + +quickmark-save + m + +set-cmd-text ":quickmark-load " + b + +set-cmd-text ":quickmark-load -t " + B + +set-cmd-text ":quickmark-load -w" + wb + +save + sf + +set-cmd-text ":set " + ss + +set-cmd-text ":set -t " + sl + +set-cmd-text ":set keybind " + sk + +zoom-out + - + +zoom-in + + + +zoom + = + +navigate prev + [[ + +navigate next + ]] + +navigate prev -t + {{ + +navigate next -t + }} + +navigate up + gu + +navigate up -t + gU + +navigate increment + + +navigate decrement + + +inspector + wi + +download-page + gd + +cancel-download + ad + +view-source + gf + +tab-focus last + + +enter-mode passthrough + + +quit + + +scroll-page 0 1 + + +scroll-page 0 -1 + + +scroll-page 0 0.5 + + +scroll-page 0 -0.5 + + +tab-focus 1 + + +tab-focus 2 + + +tab-focus 3 + + +tab-focus 4 + + +tab-focus 5 + + +tab-focus 6 + + +tab-focus 7 + + +tab-focus 8 + + +tab-focus 9 + + +home + + +stop + + +print + + +open qute:settings + Ss + +[insert] +# Keybindings for insert mode. +# Since normal keypresses are passed through, only special keys are +# supported in this mode. +# Useful hidden commands to map in this section: +# * `open-editor`: Open a texteditor with the focused field. + +open-editor + + +[hint] +# Keybindings for hint mode. +# Since normal keypresses are passed through, only special keys are +# supported in this mode. +# Useful hidden commands to map in this section: +# * `follow-hint`: Follow the currently selected hint. + +follow-hint + + +[command] +# Keybindings for command mode. +# Since normal keypresses are passed through, only special keys are +# supported in this mode. +# Useful hidden commands to map in this section: +# * `command-history-prev`: Switch to previous command in history. +# * `command-history-next`: Switch to next command in history. +# * `completion-item-prev`: Select previous item in completion. +# * `completion-item-next`: Select next item in completion. +# * `command-accept`: Execute the command currently in the commandline. + +command-history-prev + + +command-history-next + + +completion-item-prev + + + +completion-item-next + + + +command-accept + + + + +[prompt] +# Keybindings for prompts in the status line. +# You can bind normal keys in this mode, but they will be only active +# when a yes/no-prompt is asked. For other prompt modes, you can only +# bind special keys. +# Useful hidden commands to map in this section: +# * `prompt-accept`: Confirm the entered value. +# * `prompt-yes`: Answer yes to a yes/no question. +# * `prompt-no`: Answer no to a yes/no question. + +prompt-accept + + + + +prompt-yes + y + +prompt-no + n + +[command,prompt] + +rl-backward-char + + +rl-forward-char + + +rl-backward-word + + +rl-forward-word + + +rl-beginning-of-line + + +rl-end-of-line + + +rl-unix-line-discard + + +rl-kill-line + + +rl-kill-word + + +rl-unix-word-rubout + + +rl-yank + + +rl-delete-char + + +rl-backward-delete-char + + diff --git a/qutebrowser/quickmarks b/qutebrowser/quickmarks new file mode 100644 index 0000000..e69de29 diff --git a/qutebrowser/qutebrowser.conf b/qutebrowser/qutebrowser.conf new file mode 100644 index 0000000..7c95f98 --- /dev/null +++ b/qutebrowser/qutebrowser.conf @@ -0,0 +1,986 @@ +# vim: ft=dosini + +# Configfile for qutebrowser. +# +# WARNING: +# +# This config file will be OVERWRITTEN when closing qutebrowser. +# Close qutebrowser before changing this file, or YOUR CHANGES WILL BE LOST. +# +# This configfile is parsed by python's configparser in extended +# interpolation mode. The format is very INI-like, so there are +# categories like [general] with "key = value"-pairs. +# +# Note that you shouldn't add your own comments, as this file is +# regenerated every time the config is saved. +# +# Interpolation looks like ${value} or ${section:value} and will be +# replaced by the respective value. +# +# This is the default config, so if you want to remove anything from +# here (as opposed to change/add), for example a keybinding, set it to +# an empty value. +# +# You will need to escape the following values: +# - # at the start of the line (at the first position of the key) (\#) +# - $ in a value ($$) + +[general] +# General/miscellaneous options. +# +# ignore-case (bool): +# Whether to find text on a page case-insensitively. +# true: Search case-insensitively +# false: Search case-sensitively +# smart: Search case-sensitively if there are capital chars +# Default: smart +# +# wrap-search (bool): +# Whether to wrap finding text to the top when arriving at the end. +# Valid values: true, false +# Default: true +# +# startpage (string-list): +# The default page(s) to open at the start, separated by commas. +# Default: https://www.duckduckgo.com +# +# auto-search: +# Whether to start a search when something else than a URL is +# entered. +# naive: Use simple/naive check. +# dns: Use DNS requests (might be slow!). +# false: Never search automatically. +# Default: naive +# +# auto-save-config (bool): +# Whether to save the config automatically on quit. +# Valid values: true, false +# Default: true +# +# editor (shell-command): +# The editor (and arguments) to use for the `open-editor` command. +# Use `{}` for the filename. The value gets split like in a shell, +# so you can use `"` or `'` to quote arguments. +# Default: gvim -f "{}" +# +# editor-encoding (encoding): +# Encoding to use for editor. +# Default: utf-8 +# +# private-browsing (bool): +# Do not record visited pages in the history or store web page +# icons. +# Valid values: true, false +# Default: false +# +# developer-extras (bool): +# Enable extra tools for Web developers. +# This needs to be enabled for `:inspector` to work and also adds an +# _Inspect_ entry to the context menu. +# Valid values: true, false +# Default: false +# +# print-element-backgrounds (bool): +# Whether the background color and images are also drawn when the +# page is printed. +# Valid values: true, false +# Default: true +# +# xss-auditing (bool): +# Whether load requests should be monitored for cross-site scripting +# attempts. +# Suspicious scripts will be blocked and reported in the inspector's +# JavaScript console. Enabling this feature might have an impact on +# performance. +# Valid values: true, false +# Default: false +# +# site-specific-quirks (bool): +# Enable workarounds for broken sites. +# Valid values: true, false +# Default: true +# +# default-encoding (string): +# Default encoding to use for websites. +# The encoding must be a string describing an encoding such as +# _utf-8_, _iso-8859-1_, etc. If left empty a default value will be +# used. +# Default: +# +# new-instance-open-target: +# How to open links in an existing instance if a new one is +# launched. +# tab: Open a new tab in the existing window and activate it. +# tab-silent: Open a new tab in the existing window without +# activating it. +# window: Open in a new window. +# Default: window +ignore-case = smart +wrap-search = true +startpage = https://www.duckduckgo.com +auto-search = naive +auto-save-config = true +editor = urxvt -e vim "{}" +editor-encoding = utf-8 +private-browsing = false +developer-extras = true +print-element-backgrounds = true +xss-auditing = false +site-specific-quirks = true +default-encoding = +new-instance-open-target = tab + +[ui] +# General options related to the user interface. +# +# zoom-levels (perc-list): +# The available zoom levels, separated by commas. +# Default: +# 25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,250%,300%,400%,500% +# +# default-zoom (percentage): +# The default zoom level. +# Default: 100% +# +# message-timeout (int): +# Time (in ms) to show messages in the statusbar for. +# Default: 2000 +# +# confirm-quit (string-list): +# Whether to confirm quitting the application. +# always: Always show a confirmation. +# multiple-tabs: Show a confirmation if multiple tabs are +# opened. +# downloads: Show a confirmation if downloads are running +# never: Never show a confirmation. +# Default: never +# +# display-statusbar-messages (bool): +# Whether to display javascript statusbar messages. +# Valid values: true, false +# Default: false +# +# zoom-text-only (bool): +# Whether the zoom factor on a frame applies only to the text or to +# all content. +# Valid values: true, false +# Default: false +# +# frame-flattening (bool): +# Whether to expand each subframe to its contents. +# This will flatten all the frames to become one scrollable page. +# Valid values: true, false +# Default: false +# +# user-stylesheet (user-stylesheet): +# User stylesheet to use (absolute filename or CSS string). +# Default: ::-webkit-scrollbar { width: 0px; height: 0px; } +# +# css-media-type (string): +# Set the CSS media type. +# Default: +# +# remove-finished-downloads (bool): +# Whether to remove finished downloads automatically. +# Valid values: true, false +# Default: false +zoom-levels = 25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,250%,300%,400%,500% +default-zoom = 100% +message-timeout = 2000 +confirm-quit = downloads +display-statusbar-messages = false +zoom-text-only = false +frame-flattening = false +user-stylesheet = ::-webkit-scrollbar { width: 0px; height: 0px; } +css-media-type = +remove-finished-downloads = false + +[network] +# Settings related to the network. +# +# do-not-track (bool): +# Value to send in the `DNT` header. +# Valid values: true, false +# Default: true +# +# accept-language (string): +# Value to send in the `accept-language` header. +# Default: en-US,en +# +# user-agent (string): +# User agent to send. Empty to send the default. +# Default: +# +# proxy: +# The proxy to use. +# In addition to the listed values, you can use a `socks://...` or +# `http://...` URL. +# system: Use the system wide proxy. +# none: Don't use any proxy +# Default: system +# +# proxy-dns-requests (bool): +# Whether to send DNS requests over the configured proxy. +# Valid values: true, false +# Default: true +# +# ssl-strict (bool): +# Whether to validate SSL handshakes. +# Valid values: true, false, ask +# Default: ask +# +# dns-prefetch (bool): +# Whether to try to pre-fetch DNS entries to speed up browsing. +# Valid values: true, false +# Default: true +do-not-track = true +accept-language = en-US,en,de,fr +user-agent = +proxy = system +proxy-dns-requests = true +ssl-strict = ask +dns-prefetch = true + +[completion] +# Options related to completion and command history. +# +# show (bool): +# Whether to show the autocompletion window. +# Valid values: true, false +# Default: true +# +# height (percentage-or-int): +# The height of the completion, in px or as percentage of the +# window. +# Default: 50% +# +# history-length (int): +# How many commands to save in the history. +# 0: no history / -1: unlimited +# Default: 100 +# +# quick-complete (bool): +# Whether to move on to the next part when there's only one possible +# completion left. +# Valid values: true, false +# Default: true +# +# shrink (bool): +# Whether to shrink the completion to be smaller than the configured +# size if there are no scrollbars. +# Valid values: true, false +# Default: false +show = true +height = 150 +history-length = 100 +quick-complete = false +shrink = true + +[input] +# Options related to input modes. +# +# timeout (int): +# Timeout for ambiguous keybindings. +# Default: 500 +# +# insert-mode-on-plugins (bool): +# Whether to switch to insert mode when clicking flash and other +# plugins. +# Valid values: true, false +# Default: false +# +# auto-leave-insert-mode (bool): +# Whether to leave insert mode if a non-editable element is clicked. +# Valid values: true, false +# Default: true +# +# auto-insert-mode (bool): +# Whether to automatically enter insert mode if an editable element +# is focused after page load. +# Valid values: true, false +# Default: false +# +# forward-unbound-keys: +# Whether to forward unbound keys to the webview in normal mode. +# all: Forward all unbound keys. +# auto: Forward unbound non-alphanumeric keys. +# none: Don't forward any keys. +# Default: auto +# +# spatial-navigation (bool): +# Enables or disables the Spatial Navigation feature +# Spatial navigation consists in the ability to navigate between +# focusable elements in a Web page, such as hyperlinks and form +# controls, by using Left, Right, Up and Down arrow keys. For +# example, if a user presses the Right key, heuristics determine +# whether there is an element he might be trying to reach towards +# the right and which element he probably wants. +# Valid values: true, false +# Default: false +# +# links-included-in-focus-chain (bool): +# Whether hyperlinks should be included in the keyboard focus chain. +# Valid values: true, false +# Default: true +timeout = 500 +insert-mode-on-plugins = false +auto-leave-insert-mode = true +auto-insert-mode = false +forward-unbound-keys = auto +spatial-navigation = false +links-included-in-focus-chain = true + +[tabs] +# Configuration of the tab bar. +# +# background-tabs (bool): +# Whether to open new tabs (middleclick/ctrl+click) in background. +# Valid values: true, false +# Default: false +# +# select-on-remove: +# Which tab to select when the focused tab is removed. +# left: Select the tab on the left. +# right: Select the tab on the right. +# previous: Select the previously selected tab. +# Default: right +# +# new-tab-position: +# How new tabs are positioned. +# left: On the left of the current tab. +# right: On the right of the current tab. +# first: At the left end. +# last: At the right end. +# Default: right +# +# new-tab-position-explicit: +# How new tabs opened explicitely are positioned. +# left: On the left of the current tab. +# right: On the right of the current tab. +# first: At the left end. +# last: At the right end. +# Default: last +# +# last-close: +# Behaviour when the last tab is closed. +# ignore: Don't do anything. +# blank: Load a blank page. +# close: Close the window. +# Default: ignore +# +# auto-hide (bool): +# Hide the tabbar if only one tab is open. +# Valid values: true, false +# Default: false +# +# wrap (bool): +# Whether to wrap when changing tabs. +# Valid values: true, false +# Default: true +# +# movable (bool): +# Whether tabs should be movable. +# Valid values: true, false +# Default: true +# +# close-mouse-button: +# On which mouse button to close tabs. +# right: Close tabs on right-click. +# middle: Close tabs on middle-click. +# none: Don't close tabs using the mouse. +# Default: middle +# +# position: +# The position of the tab bar. +# Valid values: north, south, east, west +# Default: north +# +# show-favicons (bool): +# Whether to show favicons in the tab bar. +# Valid values: true, false +# Default: true +# +# width (percentage-or-int): +# The width of the tab bar if it's vertical, in px or as percentage +# of the window. +# Default: 20% +# +# indicator-width (int): +# Width of the progress indicator (0 to disable). +# Default: 3 +# +# indicator-space (int): +# Spacing between tab edge and indicator. +# Default: 3 +# +# tabs-are-windows (bool): +# Whether to open windows instead of tabs. +# Valid values: true, false +# Default: false +background-tabs = false +select-on-remove = left +new-tab-position = right +new-tab-position-explicit = last +last-close = ignore +auto-hide = false +wrap = true +movable = true +close-mouse-button = middle +position = north +show-favicons = true +width = 20% +indicator-width = 3 +indicator-space = 3 +tabs-are-windows = false + +[storage] +# Settings related to cache and storage. +# +# download-directory (directory): +# The directory to save downloads to. An empty value selects a +# sensible os-specific default. +# Default: +# +# maximum-pages-in-cache (int): +# The maximum number of pages to hold in the memory page cache. +# The Page Cache allows for a nicer user experience when navigating +# forth or back to pages in the forward/back history, by pausing and +# resuming up to _n_ pages. +# For more information about the feature, please refer to: +# http://webkit.org/blog/427/webkit-page-cache-i-the-basics/ +# Default: +# +# object-cache-capacities (bytes-list): +# The capacities for the memory cache for dead objects such as +# stylesheets or scripts. Syntax: cacheMinDeadCapacity, +# cacheMaxDead, totalCapacity. +# The _cacheMinDeadCapacity_ specifies the minimum number of bytes +# that dead objects should consume when the cache is under pressure. +# _cacheMaxDead_ is the maximum number of bytes that dead objects +# should consume when the cache is *not* under pressure. +# _totalCapacity_ specifies the maximum number of bytes that the +# cache should consume *overall*. +# Default: +# +# offline-storage-default-quota (bytes): +# Default quota for new offline storage databases. +# Default: +# +# offline-web-application-cache-quota (bytes): +# Quota for the offline web application cache. +# Default: +# +# offline-storage-database (bool): +# Whether support for the HTML 5 offline storage feature is enabled. +# Valid values: true, false +# Default: true +# +# offline-web-application-storage (bool): +# Whether support for the HTML 5 web application cache feature is +# enabled. +# An application cache acts like an HTTP cache in some sense. For +# documents that use the application cache via JavaScript, the +# loader engine will first ask the application cache for the +# contents, before hitting the network. +# The feature is described in details at: +# http://dev.w3.org/html5/spec/Overview.html#appcache +# Valid values: true, false +# Default: true +# +# local-storage (bool): +# Whether support for the HTML 5 local storage feature is enabled. +# Valid values: true, false +# Default: true +# +# cache-size (int): +# Size of the HTTP network cache. +# Default: 52428800 +download-directory = ~/downloads +maximum-pages-in-cache = +object-cache-capacities = +offline-storage-default-quota = +offline-web-application-cache-quota = +offline-storage-database = true +offline-web-application-storage = true +local-storage = true +cache-size = 52428800 + +[content] +# Loaded plugins/scripts and allowed actions. +# +# allow-images (bool): +# Whether images are automatically loaded in web pages. +# Valid values: true, false +# Default: true +# +# allow-javascript (bool): +# Enables or disables the running of JavaScript programs. +# Valid values: true, false +# Default: true +# +# allow-plugins (bool): +# Enables or disables plugins in Web pages. +# Qt plugins with a mimetype such as "application/x-qt-plugin" are +# not affected by this setting. +# Valid values: true, false +# Default: false +# +# javascript-can-open-windows (bool): +# Whether JavaScript programs can open new windows. +# Valid values: true, false +# Default: false +# +# javascript-can-close-windows (bool): +# Whether JavaScript programs can close windows. +# Valid values: true, false +# Default: false +# +# javascript-can-access-clipboard (bool): +# Whether JavaScript programs can read or write to the clipboard. +# Valid values: true, false +# Default: false +# +# local-content-can-access-remote-urls (bool): +# Whether locally loaded documents are allowed to access remote +# urls. +# Valid values: true, false +# Default: false +# +# local-content-can-access-file-urls (bool): +# Whether locally loaded documents are allowed to access other local +# urls. +# Valid values: true, false +# Default: true +# +# cookies-accept: +# Whether to accept cookies. +# default: Default QtWebKit behaviour. +# never: Don't accept cookies at all. +# Default: default +# +# cookies-store (bool): +# Whether to store cookies. +# Valid values: true, false +# Default: true +# +# host-block-lists (url-list): +# List of URLs of lists which contain hosts to block. +# The file can be in one of the following formats: +# - An '/etc/hosts'-like file +# - One host per line +# - A zip-file of any of the above, with either only one file, or a +# file named 'hosts' (with any extension). +# Default: +# http://www.malwaredomainlist.com/hostslist/hosts.txt,http://someonewhocares.org/hosts/hosts,http://winhelp2002.mvps.org/hosts.zip,http://malwaredomains.lehigh.edu/files/justdomains.zip,http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext +allow-images = true +allow-javascript = true +allow-plugins = false +javascript-can-open-windows = true +javascript-can-close-windows = true +javascript-can-access-clipboard = false +local-content-can-access-remote-urls = false +local-content-can-access-file-urls = true +cookies-accept = default +cookies-store = true +host-block-lists = http://www.malwaredomainlist.com/hostslist/hosts.txt,http://someonewhocares.org/hosts/hosts,http://winhelp2002.mvps.org/hosts.zip,http://malwaredomains.lehigh.edu/files/justdomains.zip,http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext + +[hints] +# Hinting settings. +# +# border (string): +# CSS border value for hints. +# Default: 1px solid #E3BE23 +# +# opacity (float): +# Opacity for hints. +# Default: 0.7 +# +# mode: +# Mode to use for hints. +# number: Use numeric hints. +# letter: Use the chars in the hints -> chars setting. +# Default: letter +# +# chars (string): +# Chars used for hint strings. +# Default: asdfghjkl +# +# uppercase (bool): +# Make chars in hint strings uppercase. +# Valid values: true, false +# Default: false +# +# auto-follow (bool): +# Whether to auto-follow a hint if there's only one left. +# Valid values: true, false +# Default: true +# +# next-regexes (regex-list): +# A comma-separated list of regexes to use for 'next' links. +# Default: \bnext\b,\bmore\b,\bnewer\b,\b[>→≫]\b,\b(>>|»)\b +# +# prev-regexes (regex-list): +# A comma-separated list of regexes to use for 'prev' links. +# Default: \bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,\b(<<|«)\b +border = 1px solid #E3BE23 +opacity = 0.7 +mode = letter +chars = aoeuidhtns +uppercase = true +auto-follow = true +next-regexes = \bnext\b,\bmore\b,\bnewer\b,\b[>→≫]\b,\b(>>|»)\b +prev-regexes = \bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,\b(<<|«)\b + +[searchengines] +# Definitions of search engines which can be used via the address bar. +# The searchengine named `DEFAULT` is used when `general -> auto-search` +# is true and something else than a URL was entered to be opened. Other +# search engines can be used via the bang-syntax, e.g. `:open +# qutebrowser !google`. The string `{}` will be replaced by the search +# term, use `{{` and `}}` for literal `{`/`}` signs. +DEFAULT = ${duckduckgo} +duckduckgo = https://duckduckgo.com/?q={} +ddg = ${duckduckgo} +google = https://encrypted.google.com/search?q={} +g = ${google} +wikipedia = http://en.wikipedia.org/w/index.php?title=Special:Search&search={} +wiki = ${wikipedia} + +[aliases] +# Aliases for commands. +# By default, no aliases are defined. Example which adds a new command +# `:qtb` to open qutebrowsers website: +# `qtb = open http://www.qutebrowser.org/` + +[colors] +# Colors used in the UI. +# A value can be in one of the following format: +# * `#RGB`/`#RRGGBB`/`#RRRGGGBBB`/`#RRRRGGGGBBBB` +# * A SVG color name as specified in http://www.w3.org/TR/SVG/types.html#ColorKeywords[the W3C specification]. +# * transparent (no color) +# * `rgb(r, g, b)` / `rgba(r, g, b, a)` (values 0-255 or percentages) +# * `hsv(h, s, v)` / `hsva(h, s, v, a)` (values 0-255, hue 0-359) +# * A gradient as explained in http://qt-project.org/doc/qt-4.8/stylesheet-reference.html#list-of-property-types[the Qt documentation] under ``Gradient''. +# The `hints.*` values are a special case as they're real CSS colors, not Qt-CSS colors. There, for a gradient, you need to use `-webkit-gradient`, see https://www.webkit.org/blog/175/introducing-css-gradients/[the WebKit documentation]. +# +# completion.fg (qcolor): +# Text color of the completion widget. +# Default: white +# +# completion.bg (qss-color): +# Background color of the completion widget. +# Default: #333333 +# +# completion.item.bg (qss-color): +# Background color of completion widget items. +# Default: ${completion.bg} +# +# completion.category.fg (qcolor): +# Foreground color of completion widget category headers. +# Default: white +# +# completion.category.bg (qss-color): +# Background color of the completion widget category headers. +# Default: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #888888, +# stop:1 #505050) +# +# completion.category.border.top (qss-color): +# Top border color of the completion widget category headers. +# Default: black +# +# completion.category.border.bottom (qss-color): +# Bottom border color of the completion widget category headers. +# Default: ${completion.category.border.top} +# +# completion.item.selected.fg (qcolor): +# Foreground color of the selected completion item. +# Default: black +# +# completion.item.selected.bg (qss-color): +# Background color of the selected completion item. +# Default: #e8c000 +# +# completion.item.selected.border.top (qss-color): +# Top border color of the completion widget category headers. +# Default: #bbbb00 +# +# completion.item.selected.border.bottom (qss-color): +# Bottom border color of the selected completion item. +# Default: ${completion.item.selected.border.top} +# +# completion.match.fg (qss-color): +# Foreground color of the matched text in the completion. +# Default: #ff4444 +# +# statusbar.bg (qss-color): +# Foreground color of the statusbar. +# Default: black +# +# statusbar.fg (qss-color): +# Foreground color of the statusbar. +# Default: white +# +# statusbar.bg.error (qss-color): +# Background color of the statusbar if there was an error. +# Default: red +# +# statusbar.bg.prompt (qss-color): +# Background color of the statusbar if there is a prompt. +# Default: darkblue +# +# statusbar.bg.insert (qss-color): +# Background color of the statusbar in insert mode. +# Default: darkgreen +# +# statusbar.progress.bg (qss-color): +# Background color of the progress bar. +# Default: white +# +# statusbar.url.fg (qss-color): +# Default foreground color of the URL in the statusbar. +# Default: ${statusbar.fg} +# +# statusbar.url.fg.success (qss-color): +# Foreground color of the URL in the statusbar on successful load. +# Default: lime +# +# statusbar.url.fg.error (qss-color): +# Foreground color of the URL in the statusbar on error. +# Default: orange +# +# statusbar.url.fg.warn (qss-color): +# Foreground color of the URL in the statusbar when there's a +# warning. +# Default: yellow +# +# statusbar.url.fg.hover (qss-color): +# Foreground color of the URL in the statusbar for hovered links. +# Default: aqua +# +# tabs.fg.odd (qcolor): +# Foreground color of unselected odd tabs. +# Default: white +# +# tabs.fg.even (qcolor): +# Foreground color of unselected even tabs. +# Default: white +# +# tabs.fg.selected (qcolor): +# Foreground color of selected tabs. +# Default: white +# +# tabs.bg.odd (qcolor): +# Background color of unselected odd tabs. +# Default: grey +# +# tabs.bg.even (qcolor): +# Background color of unselected even tabs. +# Default: darkgrey +# +# tabs.bg.selected (qcolor): +# Background color of selected tabs. +# Default: black +# +# tabs.bg.bar (qcolor): +# Background color of the tabbar. +# Default: #555555 +# +# tabs.indicator.start (qcolor): +# Color gradient start for the tab indicator. +# Default: #0000aa +# +# tabs.indicator.stop (qcolor): +# Color gradient end for the tab indicator. +# Default: #00aa00 +# +# tabs.indicator.error (qcolor): +# Color for the tab indicator on errors.. +# Default: #ff0000 +# +# tabs.indicator.system: +# Color gradient interpolation system for the tab indicator. +# rgb: Interpolate in the RGB color system. +# hsv: Interpolate in the HSV color system. +# hsl: Interpolate in the HSL color system. +# Default: rgb +# +# tabs.seperator (qss-color): +# Color for the tab seperator. +# Default: #555555 +# +# hints.fg (css-color): +# Font color for hints. +# Default: black +# +# hints.fg.match (css-color): +# Font color for the matched part of hints. +# Default: green +# +# hints.bg (css-color): +# Background color for hints. +# Default: -webkit-gradient(linear, left top, left bottom, +# color-stop(0%,#FFF785), color-stop(100%,#FFC542)) +# +# downloads.fg (qcolor): +# Foreground color for downloads. +# Default: #ffffff +# +# downloads.bg.bar (qss-color): +# Background color for the download bar. +# Default: black +# +# downloads.bg.start (qcolor): +# Color gradient start for downloads. +# Default: #0000aa +# +# downloads.bg.stop (qcolor): +# Color gradient end for downloads. +# Default: #00aa00 +# +# downloads.bg.system: +# Color gradient interpolation system for downloads. +# rgb: Interpolate in the RGB color system. +# hsv: Interpolate in the HSV color system. +# hsl: Interpolate in the HSL color system. +# Default: rgb +# +# downloads.bg.error (qcolor): +# Background color for downloads with errors. +# Default: red +completion.fg = white +completion.bg = #333333 +completion.item.bg = ${completion.bg} +completion.category.fg = white +completion.category.bg = qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #888888, stop:1 #505050) +completion.category.border.top = black +completion.category.border.bottom = ${completion.category.border.top} +completion.item.selected.fg = black +completion.item.selected.bg = #e8c000 +completion.item.selected.border.top = #bbbb00 +completion.item.selected.border.bottom = ${completion.item.selected.border.top} +completion.match.fg = #ff4444 +statusbar.bg = black +statusbar.fg = white +statusbar.bg.error = red +statusbar.bg.prompt = darkblue +statusbar.bg.insert = darkgreen +statusbar.progress.bg = white +statusbar.url.fg = ${statusbar.fg} +statusbar.url.fg.success = lime +statusbar.url.fg.error = orange +statusbar.url.fg.warn = yellow +statusbar.url.fg.hover = aqua +tabs.fg.odd = white +tabs.fg.even = white +tabs.fg.selected = white +tabs.bg.odd = grey +tabs.bg.even = darkgrey +tabs.bg.selected = black +tabs.bg.bar = #555555 +tabs.indicator.start = #0000aa +tabs.indicator.stop = #00aa00 +tabs.indicator.error = #ff0000 +tabs.indicator.system = rgb +tabs.seperator = #555555 +hints.fg = black +hints.fg.match = green +hints.bg = -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFF785), color-stop(100%,#FFC542)) +downloads.fg = #ffffff +downloads.bg.bar = black +downloads.bg.start = #0000aa +downloads.bg.stop = #00aa00 +downloads.bg.system = rgb +downloads.bg.error = red + +[fonts] +# Fonts used for the UI, with optional style/weight/size. +# * Style: `normal`/`italic`/`oblique` +# * Weight: `normal`, `bold`, `100`..`900` +# * Size: _number_ `px`/`pt` +# +# _monospace (font): +# Default monospace fonts. +# Default: Terminus, Monospace, "DejaVu Sans Mono", Monaco, +# "Bitstream Vera Sans Mono", "Andale Mono", "Liberation Mono", +# "Courier New", Courier, monospace, Fixed, Consolas, Terminal +# +# completion (font): +# Font used in the completion widget. +# Default: 8pt ${_monospace} +# +# tabbar (font): +# Font used in the tabbar. +# Default: 8pt ${_monospace} +# +# statusbar (font): +# Font used in the statusbar. +# Default: 8pt ${_monospace} +# +# downloads (font): +# Font used for the downloadbar. +# Default: 8pt ${_monospace} +# +# hints (font): +# Font used for the hints. +# Default: bold 12px Monospace +# +# debug-console (font): +# Font used for the debugging console. +# Default: 8pt ${_monospace} +# +# web-family-standard (string): +# Font family for standard fonts. +# Default: +# +# web-family-fixed (string): +# Font family for fixed fonts. +# Default: +# +# web-family-serif (string): +# Font family for serif fonts. +# Default: +# +# web-family-sans-serif (string): +# Font family for sans-serif fonts. +# Default: +# +# web-family-cursive (string): +# Font family for cursive fonts. +# Default: +# +# web-family-fantasy (string): +# Font family for fantasy fonts. +# Default: +# +# web-size-minimum (int): +# The hard minimum font size. +# Default: +# +# web-size-minimum-logical (int): +# The minimum logical font size that is applied when zooming out. +# Default: +# +# web-size-default (int): +# The default font size for regular text. +# Default: +# +# web-size-default-fixed (int): +# The default font size for fixed-pitch text. +# Default: +_monospace = Terminus, Monospace, "DejaVu Sans Mono", Monaco, "Bitstream Vera Sans Mono", "Andale Mono", "Liberation Mono", "Courier New", Courier, monospace, Fixed, Consolas, Terminal +completion = 8pt ${_monospace} +tabbar = 8pt ${_monospace} +statusbar = 8pt ${_monospace} +downloads = 8pt ${_monospace} +hints = bold 12px Monospace +debug-console = 8pt ${_monospace} +web-family-standard = +web-family-fixed = +web-family-serif = +web-family-sans-serif = +web-family-cursive = +web-family-fantasy = +web-size-minimum = +web-size-minimum-logical = +web-size-default = +web-size-default-fixed = diff --git a/vim/vimrc b/vim/vimrc index 17e2a1e..9de1144 100644 --- a/vim/vimrc +++ b/vim/vimrc @@ -410,6 +410,7 @@ nnoremap gs :Gstatus nnoremap gd :Gdiff nnoremap gc :tab Gcommit -v nnoremap ga :Gwrite +nnoremap gb :Gblame " NERDTree {{{2 " open/close NERDTree with \e diff --git a/weechat/alias.conf b/weechat/alias.conf index d1611cc..51a5bb0 100644 --- a/weechat/alias.conf +++ b/weechat/alias.conf @@ -1,5 +1,5 @@ # -# alias.conf -- weechat v1.0.1 +# alias.conf -- weechat v1.1 # [cmd] diff --git a/weechat/aspell.conf b/weechat/aspell.conf index aa0bd00..4fbeb6e 100644 --- a/weechat/aspell.conf +++ b/weechat/aspell.conf @@ -1,5 +1,5 @@ # -# aspell.conf -- weechat v1.0.1 +# aspell.conf -- weechat v1.1 # [color] diff --git a/weechat/buffer_autoset.conf b/weechat/buffer_autoset.conf index 23433c1..301fe65 100644 --- a/weechat/buffer_autoset.conf +++ b/weechat/buffer_autoset.conf @@ -1,5 +1,5 @@ # -# buffer_autoset.conf -- weechat v1.0.1 +# buffer_autoset.conf -- weechat v1.1 # [buffer] diff --git a/weechat/buffers.conf b/weechat/buffers.conf index e62c7ec..d04517f 100644 --- a/weechat/buffers.conf +++ b/weechat/buffers.conf @@ -1,5 +1,5 @@ # -# buffers.conf -- weechat v1.0.1 +# buffers.conf -- weechat v1.1 # [color] diff --git a/weechat/charset.conf b/weechat/charset.conf index aadbdae..ccb87aa 100644 --- a/weechat/charset.conf +++ b/weechat/charset.conf @@ -1,5 +1,5 @@ # -# charset.conf -- weechat v1.0.1 +# charset.conf -- weechat v1.1 # [default] diff --git a/weechat/exec.conf b/weechat/exec.conf index 0f713aa..895c99e 100644 --- a/weechat/exec.conf +++ b/weechat/exec.conf @@ -1,5 +1,5 @@ # -# exec.conf -- weechat v1.0.1 +# exec.conf -- weechat v1.1 # [command] diff --git a/weechat/iset.conf b/weechat/iset.conf index aed2cbb..8d6e318 100644 --- a/weechat/iset.conf +++ b/weechat/iset.conf @@ -1,5 +1,5 @@ # -# iset.conf -- weechat v1.0.1 +# iset.conf -- weechat v1.1 # [color] diff --git a/weechat/logger.conf b/weechat/logger.conf index 9a9cde6..c98c4a0 100644 --- a/weechat/logger.conf +++ b/weechat/logger.conf @@ -1,5 +1,5 @@ # -# logger.conf -- weechat v1.0.1 +# logger.conf -- weechat v1.1 # [look] diff --git a/weechat/perl/buffers.pl b/weechat/perl/buffers.pl index ef21fdd..472f6e9 100644 --- a/weechat/perl/buffers.pl +++ b/weechat/perl/buffers.pl @@ -20,6 +20,8 @@ # # History: # +# 2014-12-12 +# v5.0: fix cropping non-latin buffer names # 2014-08-29, Patrick Steinhardt : # v4.9: add support for specifying custom buffer names # 2014-07-19, Sebastien Helleu : @@ -162,7 +164,7 @@ use strict; use Encode qw( decode encode ); # -----------------------------[ internal ]------------------------------------- my $SCRIPT_NAME = "buffers"; -my $SCRIPT_VERSION = "4.9"; +my $SCRIPT_VERSION = "5.0"; my $BUFFERS_CONFIG_FILE_NAME = "buffers"; my $buffers_config_file; @@ -1386,7 +1388,8 @@ sub build_buffers if (weechat::config_integer($options{"name_size_max"}) >= 1) # check max_size of buffer name { - $str .= encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"}))); + $name = decode("UTF-8", $name); + $str .= encode("UTF-8", substr($name, 0, weechat::config_integer($options{"name_size_max"}))); $str .= weechat::color(weechat::config_color( $options{"color_number_char"})).weechat::config_string($options{"name_crop_suffix"}) if (length($name) > weechat::config_integer($options{"name_size_max"})); $str .= add_inactive_parentless($buffer->{"type"}, $buffer->{"nicks_count"}); $str .= add_hotlist_count($buffer->{"pointer"}, %hotlist); diff --git a/weechat/plugins.conf b/weechat/plugins.conf index c4ef917..4d23b88 100644 --- a/weechat/plugins.conf +++ b/weechat/plugins.conf @@ -1,5 +1,5 @@ # -# plugins.conf -- weechat v1.0.1 +# plugins.conf -- weechat v1.1 # [var] @@ -38,6 +38,13 @@ perl.highmon.nick_suffix = ">" perl.highmon.output = "buffer" perl.highmon.short_names = "on" python.check_license = "off" +python.grep.clear_buffer = "off" +python.grep.default_tail_head = "10" +python.grep.go_to_buffer = "on" +python.grep.log_filter = "" +python.grep.max_lines = "4000" +python.grep.show_summary = "on" +python.grep.size_limit = "2048" ruby.check_license = "off" tcl.check_license = "off" diff --git a/weechat/python/autoload/grep.py b/weechat/python/autoload/grep.py new file mode 120000 index 0000000..87d4ca7 --- /dev/null +++ b/weechat/python/autoload/grep.py @@ -0,0 +1 @@ +../grep.py \ No newline at end of file diff --git a/weechat/python/grep.py b/weechat/python/grep.py new file mode 100644 index 0000000..6d08ecd --- /dev/null +++ b/weechat/python/grep.py @@ -0,0 +1,1718 @@ +# -*- coding: utf-8 -*- +### +# Copyright (c) 2009-2011 by Elián Hanisch +# +# 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 3 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, see . +### + +### +# Search in Weechat buffers and logs (for Weechat 0.3.*) +# +# Inspired by xt's grep.py +# Originally I just wanted to add some fixes in grep.py, but then +# I got carried away and rewrote everything, so new script. +# +# Commands: +# * /grep +# Search in logs or buffers, see /help grep +# * /logs: +# Lists logs in ~/.weechat/logs, see /help logs +# +# Settings: +# * plugins.var.python.grep.clear_buffer: +# Clear the results buffer before each search. Valid values: on, off +# +# * plugins.var.python.grep.go_to_buffer: +# Automatically go to grep buffer when search is over. Valid values: on, off +# +# * plugins.var.python.grep.log_filter: +# Coma separated list of patterns that grep will use for exclude logs, e.g. +# if you use '*server/*' any log in the 'server' folder will be excluded +# when using the command '/grep log' +# +# * plugins.var.python.grep.show_summary: +# Shows summary for each log. Valid values: on, off +# +# * plugins.var.python.grep.max_lines: +# Grep will only print the last matched lines that don't surpass the value defined here. +# +# * plugins.var.python.grep.size_limit: +# Size limit in KiB, is used for decide whenever grepping should run in background or not. If +# the logs to grep have a total size bigger than this value then grep run as a new process. +# It can be used for force or disable background process, using '0' forces to always grep in +# background, while using '' (empty string) will disable it. +# +# * plugins.var.python.grep.default_tail_head: +# Config option for define default number of lines returned when using --head or --tail options. +# Can be overriden in the command with --number option. +# +# +# TODO: +# * try to figure out why hook_process chokes in long outputs (using a tempfile as a +# workaround now) +# * possibly add option for defining time intervals +# +# +# History: +# 2014-03-29, Felix Eckhofer +# version 0.7.3: fix typo +# +# 2011-01-09 +# version 0.7.2: bug fixes +# +# 2010-11-15 +# version 0.7.1: +# * use TempFile so temporal files are guaranteed to be deleted. +# * enable Archlinux workaround. +# +# 2010-10-26 +# version 0.7: +# * added templates. +# * using --only-match shows only unique strings. +# * fixed bug that inverted -B -A switches when used with -t +# +# 2010-10-14 +# version 0.6.8: by xt +# * supress highlights when printing in grep buffer +# +# 2010-10-06 +# version 0.6.7: by xt +# * better temporary file: +# use tempfile.mkstemp. to create a temp file in log dir, +# makes it safer with regards to write permission and multi user +# +# 2010-04-08 +# version 0.6.6: bug fixes +# * use WEECHAT_LIST_POS_END in log file completion, makes completion faster +# * disable bytecode if using python 2.6 +# * use single quotes in command string +# * fix bug that could change buffer's title when using /grep stop +# +# 2010-01-24 +# version 0.6.5: disable bytecode is a 2.6 feature, instead, resort to delete the bytecode manually +# +# 2010-01-19 +# version 0.6.4: bug fix +# version 0.6.3: added options --invert --only-match (replaces --exact, which is still available +# but removed from help) +# * use new 'irc_nick_color' info +# * don't generate bytecode when spawning a new process +# * show active options in buffer title +# +# 2010-01-17 +# version 0.6.2: removed 2.6-ish code +# version 0.6.1: fixed bug when grepping in grep's buffer +# +# 2010-01-14 +# version 0.6.0: implemented grep in background +# * improved context lines presentation. +# * grepping for big (or many) log files runs in a weechat_process. +# * added /grep stop. +# * added 'size_limit' option +# * fixed a infolist leak when grepping buffers +# * added 'default_tail_head' option +# * results are sort by line count +# * don't die if log is corrupted (has NULL chars in it) +# * changed presentation of /logs +# * log path completion doesn't suck anymore +# * removed all tabs, because I learned how to configure Vim so that spaces aren't annoying +# anymore. This was the script's original policy. +# +# 2010-01-05 +# version 0.5.5: rename script to 'grep.py' (FlashCode ). +# +# 2010-01-04 +# version 0.5.4.1: fix index error when using --after/before-context options. +# +# 2010-01-03 +# version 0.5.4: new features +# * added --after-context and --before-context options. +# * added --context as a shortcut for using both -A -B options. +# +# 2009-11-06 +# version 0.5.3: improvements for long grep output +# * grep buffer input accepts the same flags as /grep for repeat a search with different +# options. +# * tweaks in grep's output. +# * max_lines option added for limit grep's output. +# * code in update_buffer() optimized. +# * time stats in buffer title. +# * added go_to_buffer config option. +# * added --buffer for search only in buffers. +# * refactoring. +# +# 2009-10-12, omero +# version 0.5.2: made it python-2.4.x compliant +# +# 2009-08-17 +# version 0.5.1: some refactoring, show_summary option added. +# +# 2009-08-13 +# version 0.5: rewritten from xt's grep.py +# * fixed searching in non weechat logs, for cases like, if you're +# switching from irssi and rename and copy your irssi logs to %h/logs +# * fixed "timestamp rainbow" when you /grep in grep's buffer +# * allow to search in other buffers other than current or in logs +# of currently closed buffers with cmd 'buffer' +# * allow to search in any log file in %h/logs with cmd 'log' +# * added --count for return the number of matched lines +# * added --matchcase for case sensible search +# * added --hilight for color matches +# * added --head and --tail options, and --number +# * added command /logs for list files in %h/logs +# * added config option for clear the buffer before a search +# * added config option for filter logs we don't want to grep +# * added the posibility to repeat last search with another regexp by writing +# it in grep's buffer +# * changed spaces for tabs in the code, which is my preference +# +### + +from os import path +import sys, getopt, time, os, re, tempfile + +try: + import weechat + from weechat import WEECHAT_RC_OK, prnt, prnt_date_tags + import_ok = True +except ImportError: + import_ok = False + +SCRIPT_NAME = "grep" +SCRIPT_AUTHOR = "Elián Hanisch " +SCRIPT_VERSION = "0.7.3" +SCRIPT_LICENSE = "GPL3" +SCRIPT_DESC = "Search in buffers and logs" +SCRIPT_COMMAND = "grep" + +### Default Settings ### +settings = { +'clear_buffer' : 'off', +'log_filter' : '', +'go_to_buffer' : 'on', +'max_lines' : '4000', +'show_summary' : 'on', +'size_limit' : '2048', +'default_tail_head' : '10', +} + +### Class definitions ### +class linesDict(dict): + """ + Class for handling matched lines in more than one buffer. + linesDict[buffer_name] = matched_lines_list + """ + def __setitem__(self, key, value): + assert isinstance(value, list) + if key not in self: + dict.__setitem__(self, key, value) + else: + dict.__getitem__(self, key).extend(value) + + def get_matches_count(self): + """Return the sum of total matches stored.""" + if dict.__len__(self): + return sum(map(lambda L: L.matches_count, self.itervalues())) + else: + return 0 + + def __len__(self): + """Return the sum of total lines stored.""" + if dict.__len__(self): + return sum(map(len, self.itervalues())) + else: + return 0 + + def __str__(self): + """Returns buffer count or buffer name if there's just one stored.""" + n = len(self.keys()) + if n == 1: + return self.keys()[0] + elif n > 1: + return '%s logs' %n + else: + return '' + + def items(self): + """Returns a list of items sorted by line count.""" + items = dict.items(self) + items.sort(key=lambda i: len(i[1])) + return items + + def items_count(self): + """Returns a list of items sorted by match count.""" + items = dict.items(self) + items.sort(key=lambda i: i[1].matches_count) + return items + + def strip_separator(self): + for L in self.itervalues(): + L.strip_separator() + + def get_last_lines(self, n): + total_lines = len(self) + #debug('total: %s n: %s' %(total_lines, n)) + if n >= total_lines: + # nothing to do + return + for k, v in reversed(self.items()): + l = len(v) + if n > 0: + if l > n: + del v[:l-n] + v.stripped_lines = l-n + n -= l + else: + del v[:] + v.stripped_lines = l + +class linesList(list): + """Class for list of matches, since sometimes I need to add lines that aren't matches, I need an + independent counter.""" + _sep = '...' + def __init__(self, *args): + list.__init__(self, *args) + self.matches_count = 0 + self.stripped_lines = 0 + + def append(self, item): + """Append lines, can be a string or a list with strings.""" + if isinstance(item, str): + list.append(self, item) + else: + self.extend(item) + + def append_separator(self): + """adds a separator into the list, makes sure it doen't add two together.""" + s = self._sep + if (self and self[-1] != s) or not self: + self.append(s) + + def onlyUniq(self): + s = set(self) + del self[:] + self.extend(s) + + def count_match(self, item=None): + if item is None or isinstance(item, str): + self.matches_count += 1 + else: + self.matches_count += len(item) + + def strip_separator(self): + """removes separators if there are first or/and last in the list.""" + if self: + s = self._sep + if self[0] == s: + del self[0] + if self[-1] == s: + del self[-1] + +### Misc functions ### +now = time.time +def get_size(f): + try: + return os.stat(f).st_size + except OSError: + return 0 + +sizeDict = {0:'b', 1:'KiB', 2:'MiB', 3:'GiB', 4:'TiB'} +def human_readable_size(size): + power = 0 + while size > 1024: + power += 1 + size /= 1024.0 + return '%.2f %s' %(size, sizeDict.get(power, '')) + +def color_nick(nick): + """Returns coloured nick, with coloured mode if any.""" + if not nick: return '' + wcolor = weechat.color + config_string = lambda s : weechat.config_string(weechat.config_get(s)) + config_int = lambda s : weechat.config_integer(weechat.config_get(s)) + # prefix and suffix + prefix = config_string('irc.look.nick_prefix') + suffix = config_string('irc.look.nick_suffix') + prefix_c = suffix_c = wcolor(config_string('weechat.color.chat_delimiters')) + if nick[0] == prefix: + nick = nick[1:] + else: + prefix = prefix_c = '' + if nick[-1] == suffix: + nick = nick[:-1] + suffix = wcolor(color_delimiter) + suffix + else: + suffix = suffix_c = '' + # nick mode + modes = '@!+%' + if nick[0] in modes: + mode, nick = nick[0], nick[1:] + mode_color = wcolor(config_string('weechat.color.nicklist_prefix%d' \ + %(modes.find(mode) + 1))) + else: + mode = mode_color = '' + # nick color + nick_color = weechat.info_get('irc_nick_color', nick) + if not nick_color: + # probably we're in WeeChat 0.3.0 + #debug('no irc_nick_color') + color_nicks_number = config_int('weechat.look.color_nicks_number') + idx = (sum(map(ord, nick))%color_nicks_number) + 1 + nick_color = wcolor(config_string('weechat.color.chat_nick_color%02d' %idx)) + return ''.join((prefix_c, prefix, mode_color, mode, nick_color, nick, suffix_c, suffix)) + +### Config and value validation ### +boolDict = {'on':True, 'off':False} +def get_config_boolean(config): + value = weechat.config_get_plugin(config) + try: + return boolDict[value] + except KeyError: + default = settings[config] + error("Error while fetching config '%s'. Using default value '%s'." %(config, default)) + error("'%s' is invalid, allowed: 'on', 'off'" %value) + return boolDict[default] + +def get_config_int(config, allow_empty_string=False): + value = weechat.config_get_plugin(config) + try: + return int(value) + except ValueError: + if value == '' and allow_empty_string: + return value + default = settings[config] + error("Error while fetching config '%s'. Using default value '%s'." %(config, default)) + error("'%s' is not a number." %value) + return int(default) + +def get_config_log_filter(): + filter = weechat.config_get_plugin('log_filter') + if filter: + return filter.split(',') + else: + return [] + +def get_home(): + home = weechat.config_string(weechat.config_get('logger.file.path')) + return home.replace('%h', weechat.info_get('weechat_dir', '')) + +def strip_home(s, dir=''): + """Strips home dir from the begging of the log path, this makes them sorter.""" + if not dir: + global home_dir + dir = home_dir + l = len(dir) + if s[:l] == dir: + return s[l:] + return s + +### Messages ### +script_nick = SCRIPT_NAME +def error(s, buffer=''): + """Error msg""" + prnt(buffer, '%s%s %s' %(weechat.prefix('error'), script_nick, s)) + if weechat.config_get_plugin('debug'): + import traceback + if traceback.sys.exc_type: + trace = traceback.format_exc() + prnt('', trace) + +def say(s, buffer=''): + """normal msg""" + prnt_date_tags(buffer, 0, 'no_highlight', '%s\t%s' %(script_nick, s)) + + + +### Log files and buffers ### +cache_dir = {} # note: don't remove, needed for completion if the script was loaded recently +def dir_list(dir, filter_list=(), filter_excludes=True, include_dir=False): + """Returns a list of files in 'dir' and its subdirs.""" + global cache_dir + from os import walk + from fnmatch import fnmatch + #debug('dir_list: listing in %s' %dir) + key = (dir, include_dir) + try: + return cache_dir[key] + except KeyError: + pass + + filter_list = filter_list or get_config_log_filter() + dir_len = len(dir) + if filter_list: + def filter(file): + file = file[dir_len:] # pattern shouldn't match home dir + for pattern in filter_list: + if fnmatch(file, pattern): + return filter_excludes + return not filter_excludes + else: + filter = lambda f : not filter_excludes + + file_list = [] + extend = file_list.extend + join = path.join + def walk_path(): + for basedir, subdirs, files in walk(dir): + #if include_dir: + # subdirs = map(lambda s : join(s, ''), subdirs) + # files.extend(subdirs) + files_path = map(lambda f : join(basedir, f), files) + files_path = [ file for file in files_path if not filter(file) ] + extend(files_path) + + walk_path() + cache_dir[key] = file_list + #debug('dir_list: got %s' %str(file_list)) + return file_list + +def get_file_by_pattern(pattern, all=False): + """Returns the first log whose path matches 'pattern', + if all is True returns all logs that matches.""" + if not pattern: return [] + #debug('get_file_by_filename: searching for %s.' %pattern) + # do envvar expandsion and check file + file = path.expanduser(pattern) + file = path.expandvars(file) + if path.isfile(file): + return [file] + # lets see if there's a matching log + global home_dir + file = path.join(home_dir, pattern) + if path.isfile(file): + return [file] + else: + from fnmatch import fnmatch + file = [] + file_list = dir_list(home_dir) + n = len(home_dir) + for log in file_list: + basename = log[n:] + if fnmatch(basename, pattern): + file.append(log) + #debug('get_file_by_filename: got %s.' %file) + if not all and file: + file.sort() + return [ file[-1] ] + return file + +def get_file_by_buffer(buffer): + """Given buffer pointer, finds log's path or returns None.""" + #debug('get_file_by_buffer: searching for %s' %buffer) + infolist = weechat.infolist_get('logger_buffer', '', '') + if not infolist: return + try: + while weechat.infolist_next(infolist): + pointer = weechat.infolist_pointer(infolist, 'buffer') + if pointer == buffer: + file = weechat.infolist_string(infolist, 'log_filename') + if weechat.infolist_integer(infolist, 'log_enabled'): + #debug('get_file_by_buffer: got %s' %file) + return file + #else: + # debug('get_file_by_buffer: got %s but log not enabled' %file) + finally: + #debug('infolist gets freed') + weechat.infolist_free(infolist) + +def get_file_by_name(buffer_name): + """Given a buffer name, returns its log path or None. buffer_name should be in 'server.#channel' + or '#channel' format.""" + #debug('get_file_by_name: searching for %s' %buffer_name) + # common mask options + config_masks = ('logger.mask.irc', 'logger.file.mask') + # since there's no buffer pointer, we try to replace some local vars in mask, like $channel and + # $server, then replace the local vars left with '*', and use it as a mask for get the path with + # get_file_by_pattern + for config in config_masks: + mask = weechat.config_string(weechat.config_get(config)) + #debug('get_file_by_name: mask: %s' %mask) + if '$name' in mask: + mask = mask.replace('$name', buffer_name) + elif '$channel' in mask or '$server' in mask: + if '.' in buffer_name and \ + '#' not in buffer_name[:buffer_name.find('.')]: # the dot isn't part of the channel name + # ^ I'm asuming channel starts with #, i'm lazy. + server, channel = buffer_name.split('.', 1) + else: + server, channel = '*', buffer_name + if '$channel' in mask: + mask = mask.replace('$channel', channel) + if '$server' in mask: + mask = mask.replace('$server', server) + # change the unreplaced vars by '*' + from string import letters + if '%' in mask: + # vars for time formatting + mask = mask.replace('%', '$') + if '$' in mask: + masks = mask.split('$') + masks = map(lambda s: s.lstrip(letters), masks) + mask = '*'.join(masks) + if mask[0] != '*': + mask = '*' + mask + #debug('get_file_by_name: using mask %s' %mask) + file = get_file_by_pattern(mask) + #debug('get_file_by_name: got file %s' %file) + if file: + return file + return None + +def get_buffer_by_name(buffer_name): + """Given a buffer name returns its buffer pointer or None.""" + #debug('get_buffer_by_name: searching for %s' %buffer_name) + pointer = weechat.buffer_search('', buffer_name) + if not pointer: + try: + infolist = weechat.infolist_get('buffer', '', '') + while weechat.infolist_next(infolist): + short_name = weechat.infolist_string(infolist, 'short_name') + name = weechat.infolist_string(infolist, 'name') + if buffer_name in (short_name, name): + #debug('get_buffer_by_name: found %s' %name) + pointer = weechat.buffer_search('', name) + return pointer + finally: + weechat.infolist_free(infolist) + #debug('get_buffer_by_name: got %s' %pointer) + return pointer + +def get_all_buffers(): + """Returns list with pointers of all open buffers.""" + buffers = [] + infolist = weechat.infolist_get('buffer', '', '') + while weechat.infolist_next(infolist): + buffers.append(weechat.infolist_pointer(infolist, 'pointer')) + weechat.infolist_free(infolist) + grep_buffer = weechat.buffer_search('python', SCRIPT_NAME) + if grep_buffer and grep_buffer in buffers: + # remove it from list + del buffers[buffers.index(grep_buffer)] + return buffers + +### Grep ### +def make_regexp(pattern, matchcase=False): + """Returns a compiled regexp.""" + if pattern in ('.', '.*', '.?', '.+'): + # because I don't need to use a regexp if we're going to match all lines + return None + # matching takes a lot more time if pattern starts or ends with .* and it isn't needed. + if pattern[:2] == '.*': + pattern = pattern[2:] + if pattern[-2:] == '.*': + pattern = pattern[:-2] + try: + if not matchcase: + regexp = re.compile(pattern, re.IGNORECASE) + else: + regexp = re.compile(pattern) + except Exception, e: + raise Exception, 'Bad pattern, %s' %e + return regexp + +def check_string(s, regexp, hilight='', exact=False): + """Checks 's' with a regexp and returns it if is a match.""" + if not regexp: + return s + + elif exact: + matchlist = regexp.findall(s) + if matchlist: + if isinstance(matchlist[0], tuple): + # join tuples (when there's more than one match group in regexp) + return [ ' '.join(t) for t in matchlist ] + return matchlist + + elif hilight: + matchlist = regexp.findall(s) + if matchlist: + if isinstance(matchlist[0], tuple): + # flatten matchlist + matchlist = [ item for L in matchlist for item in L if item ] + matchlist = list(set(matchlist)) # remove duplicates if any + # apply hilight + color_hilight, color_reset = hilight.split(',', 1) + for m in matchlist: + s = s.replace(m, '%s%s%s' % (color_hilight, m, color_reset)) + return s + + # no need for findall() here + elif regexp.search(s): + return s + +def grep_file(file, head, tail, after_context, before_context, count, regexp, hilight, exact, invert): + """Return a list of lines that match 'regexp' in 'file', if no regexp returns all lines.""" + if count: + tail = head = after_context = before_context = False + hilight = '' + elif exact: + before_context = after_context = False + hilight = '' + elif invert: + hilight = '' + #debug(' '.join(map(str, (file, head, tail, after_context, before_context)))) + + lines = linesList() + # define these locally as it makes the loop run slightly faster + append = lines.append + count_match = lines.count_match + separator = lines.append_separator + if invert: + def check(s): + if check_string(s, regexp, hilight, exact): + return None + else: + return s + else: + check = lambda s: check_string(s, regexp, hilight, exact) + + try: + file_object = open(file, 'r') + except IOError: + # file doesn't exist + return lines + if tail or before_context: + # for these options, I need to seek in the file, but is slower and uses a good deal of + # memory if the log is too big, so we do this *only* for these options. + file_lines = file_object.readlines() + + if tail: + # instead of searching in the whole file and later pick the last few lines, we + # reverse the log, search until count reached and reverse it again, that way is a lot + # faster + file_lines.reverse() + # don't invert context switches + before_context, after_context = after_context, before_context + + if before_context: + before_context_range = range(1, before_context + 1) + before_context_range.reverse() + + limit = tail or head + + line_idx = 0 + while line_idx < len(file_lines): + line = file_lines[line_idx] + line = check(line) + if line: + if before_context: + separator() + trimmed = False + for id in before_context_range: + try: + context_line = file_lines[line_idx - id] + if check(context_line): + # match in before context, that means we appended these same lines in a + # previous match, so we delete them merging both paragraphs + if not trimmed: + del lines[id - before_context - 1:] + trimmed = True + else: + append(context_line) + except IndexError: + pass + append(line) + count_match(line) + if after_context: + id, offset = 0, 0 + while id < after_context + offset: + id += 1 + try: + context_line = file_lines[line_idx + id] + _context_line = check(context_line) + if _context_line: + offset = id + context_line = _context_line # so match is hilighted with --hilight + count_match() + append(context_line) + except IndexError: + pass + separator() + line_idx += id + if limit and lines.matches_count >= limit: + break + line_idx += 1 + + if tail: + lines.reverse() + else: + # do a normal grep + limit = head + + for line in file_object: + line = check(line) + if line: + count or append(line) + count_match(line) + if after_context: + id, offset = 0, 0 + while id < after_context + offset: + id += 1 + try: + context_line = file_object.next() + _context_line = check(context_line) + if _context_line: + offset = id + context_line = _context_line + count_match() + count or append(context_line) + except StopIteration: + pass + separator() + if limit and lines.matches_count >= limit: + break + + file_object.close() + return lines + +def grep_buffer(buffer, head, tail, after_context, before_context, count, regexp, hilight, exact, + invert): + """Return a list of lines that match 'regexp' in 'buffer', if no regexp returns all lines.""" + lines = linesList() + if count: + tail = head = after_context = before_context = False + hilight = '' + elif exact: + before_context = after_context = False + #debug(' '.join(map(str, (tail, head, after_context, before_context, count, exact, hilight)))) + + # Using /grep in grep's buffer can lead to some funny effects + # We should take measures if that's the case + def make_get_line_funcion(): + """Returns a function for get lines from the infolist, depending if the buffer is grep's or + not.""" + string_remove_color = weechat.string_remove_color + infolist_string = weechat.infolist_string + grep_buffer = weechat.buffer_search('python', SCRIPT_NAME) + if grep_buffer and buffer == grep_buffer: + def function(infolist): + prefix = infolist_string(infolist, 'prefix') + message = infolist_string(infolist, 'message') + if prefix: # only our messages have prefix, ignore it + return None + return message + else: + infolist_time = weechat.infolist_time + def function(infolist): + prefix = string_remove_color(infolist_string(infolist, 'prefix'), '') + message = string_remove_color(infolist_string(infolist, 'message'), '') + date = infolist_time(infolist, 'date') + return '%s\t%s\t%s' %(date, prefix, message) + return function + get_line = make_get_line_funcion() + + infolist = weechat.infolist_get('buffer_lines', buffer, '') + if tail: + # like with grep_file() if we need the last few matching lines, we move the cursor to + # the end and search backwards + infolist_next = weechat.infolist_prev + infolist_prev = weechat.infolist_next + else: + infolist_next = weechat.infolist_next + infolist_prev = weechat.infolist_prev + limit = head or tail + + # define these locally as it makes the loop run slightly faster + append = lines.append + count_match = lines.count_match + separator = lines.append_separator + if invert: + def check(s): + if check_string(s, regexp, hilight, exact): + return None + else: + return s + else: + check = lambda s: check_string(s, regexp, hilight, exact) + + if before_context: + before_context_range = range(1, before_context + 1) + before_context_range.reverse() + + while infolist_next(infolist): + line = get_line(infolist) + if line is None: continue + line = check(line) + if line: + if before_context: + separator() + trimmed = False + for id in before_context_range: + if not infolist_prev(infolist): + trimmed = True + for id in before_context_range: + context_line = get_line(infolist) + if check(context_line): + if not trimmed: + del lines[id - before_context - 1:] + trimmed = True + else: + append(context_line) + infolist_next(infolist) + count or append(line) + count_match(line) + if after_context: + id, offset = 0, 0 + while id < after_context + offset: + id += 1 + if infolist_next(infolist): + context_line = get_line(infolist) + _context_line = check(context_line) + if _context_line: + context_line = _context_line + offset = id + count_match() + append(context_line) + else: + # in the main loop infolist_next will start again an cause an infinite loop + # this will avoid it + infolist_next = lambda x: 0 + separator() + if limit and lines.matches_count >= limit: + break + weechat.infolist_free(infolist) + + if tail: + lines.reverse() + return lines + +### this is our main grep function +hook_file_grep = None +def show_matching_lines(): + """ + Greps buffers in search_in_buffers or files in search_in_files and updates grep buffer with the + result. + """ + global pattern, matchcase, number, count, exact, hilight, invert + global tail, head, after_context, before_context + global search_in_files, search_in_buffers, matched_lines, home_dir + global time_start + matched_lines = linesDict() + #debug('buffers:%s \nlogs:%s' %(search_in_buffers, search_in_files)) + time_start = now() + + # buffers + if search_in_buffers: + regexp = make_regexp(pattern, matchcase) + for buffer in search_in_buffers: + buffer_name = weechat.buffer_get_string(buffer, 'name') + matched_lines[buffer_name] = grep_buffer(buffer, head, tail, after_context, + before_context, count, regexp, hilight, exact, invert) + + # logs + if search_in_files: + size_limit = get_config_int('size_limit', allow_empty_string=True) + background = False + if size_limit or size_limit == 0: + size = sum(map(get_size, search_in_files)) + if size > size_limit * 1024: + background = True + elif size_limit == '': + background = False + + if not background: + # run grep normally + regexp = make_regexp(pattern, matchcase) + for log in search_in_files: + log_name = strip_home(log) + matched_lines[log_name] = grep_file(log, head, tail, after_context, before_context, + count, regexp, hilight, exact, invert) + buffer_update() + else: + # we hook a process so grepping runs in background. + #debug('on background') + global hook_file_grep, script_path, bytecode + timeout = 1000*60*5 # 5 min + + quotify = lambda s: '"%s"' %s + files_string = ', '.join(map(quotify, search_in_files)) + + global tmpFile + # we keep the file descriptor as a global var so it isn't deleted until next grep + tmpFile = tempfile.NamedTemporaryFile(prefix=SCRIPT_NAME, + dir=weechat.info_get('weechat_dir', '')) + cmd = grep_process_cmd %dict(logs=files_string, head=head, pattern=pattern, tail=tail, + hilight=hilight, after_context=after_context, before_context=before_context, + exact=exact, matchcase=matchcase, home_dir=home_dir, script_path=script_path, + count=count, invert=invert, bytecode=bytecode, filename=tmpFile.name, + python=weechat.info_get('python2_bin', '') or 'python') + + #debug(cmd) + hook_file_grep = weechat.hook_process(cmd, timeout, 'grep_file_callback', tmpFile.name) + global pattern_tmpl + if hook_file_grep: + buffer_create("Searching for '%s' in %s worth of data..." %(pattern_tmpl, + human_readable_size(size))) + else: + buffer_update() + +# defined here for commodity +grep_process_cmd = """%(python)s -%(bytecode)sc ' +import sys, cPickle, os +sys.path.append("%(script_path)s") # add WeeChat script dir so we can import grep +from grep import make_regexp, grep_file, strip_home +logs = (%(logs)s, ) +try: + regexp = make_regexp("%(pattern)s", %(matchcase)s) + d = {} + for log in logs: + log_name = strip_home(log, "%(home_dir)s") + lines = grep_file(log, %(head)s, %(tail)s, %(after_context)s, %(before_context)s, + %(count)s, regexp, "%(hilight)s", %(exact)s, %(invert)s) + d[log_name] = lines + fd = open("%(filename)s", "wb") + cPickle.dump(d, fd, -1) + fd.close() +except Exception, e: + print >> sys.stderr, e' +""" + +grep_stdout = grep_stderr = '' +def grep_file_callback(filename, command, rc, stdout, stderr): + global hook_file_grep, grep_stderr, grep_stdout + global matched_lines + #debug("rc: %s\nstderr: %s\nstdout: %s" %(rc, repr(stderr), repr(stdout))) + if stdout: + grep_stdout += stdout + if stderr: + grep_stderr += stderr + if int(rc) >= 0: + + def set_buffer_error(): + grep_buffer = buffer_create() + title = weechat.buffer_get_string(grep_buffer, 'title') + title = title + ' %serror' %color_title + weechat.buffer_set(grep_buffer, 'title', title) + + try: + if grep_stderr: + error(grep_stderr) + set_buffer_error() + #elif grep_stdout: + #debug(grep_stdout) + elif path.exists(filename): + import cPickle + try: + #debug(file) + fd = open(filename, 'rb') + d = cPickle.load(fd) + matched_lines.update(d) + fd.close() + except Exception, e: + error(e) + set_buffer_error() + else: + buffer_update() + global tmpFile + tmpFile = None + finally: + grep_stdout = grep_stderr = '' + hook_file_grep = None + return WEECHAT_RC_OK + +def get_grep_file_status(): + global search_in_files, matched_lines, time_start + elapsed = now() - time_start + if len(search_in_files) == 1: + log = '%s (%s)' %(strip_home(search_in_files[0]), + human_readable_size(get_size(search_in_files[0]))) + else: + size = sum(map(get_size, search_in_files)) + log = '%s log files (%s)' %(len(search_in_files), human_readable_size(size)) + return 'Searching in %s, running for %.4f seconds. Interrupt it with "/grep stop" or "stop"' \ + ' in grep buffer.' %(log, elapsed) + +### Grep buffer ### +def buffer_update(): + """Updates our buffer with new lines.""" + global pattern_tmpl, matched_lines, pattern, count, hilight, invert, exact + time_grep = now() + + buffer = buffer_create() + if get_config_boolean('clear_buffer'): + weechat.buffer_clear(buffer) + matched_lines.strip_separator() # remove first and last separators of each list + len_total_lines = len(matched_lines) + max_lines = get_config_int('max_lines') + if not count and len_total_lines > max_lines: + weechat.buffer_clear(buffer) + + def _make_summary(log, lines, note): + return '%s matches "%s%s%s"%s in %s%s%s%s' \ + %(lines.matches_count, color_summary, pattern_tmpl, color_info, + invert and ' (inverted)' or '', + color_summary, log, color_reset, note) + + if count: + make_summary = lambda log, lines : _make_summary(log, lines, ' (not shown)') + else: + def make_summary(log, lines): + if lines.stripped_lines: + if lines: + note = ' (last %s lines shown)' %len(lines) + else: + note = ' (not shown)' + else: + note = '' + return _make_summary(log, lines, note) + + global weechat_format + if hilight: + # we don't want colors if there's match highlighting + format_line = lambda s : '%s %s %s' %split_line(s) + else: + def format_line(s): + global nick_dict, weechat_format + date, nick, msg = split_line(s) + if weechat_format: + try: + nick = nick_dict[nick] + except KeyError: + # cache nick + nick_c = color_nick(nick) + nick_dict[nick] = nick_c + nick = nick_c + return '%s%s %s%s %s' %(color_date, date, nick, color_reset, msg) + else: + #no formatting + return msg + + prnt(buffer, '\n') + print_line('Search for "%s%s%s"%s in %s%s%s.' %(color_summary, pattern_tmpl, color_info, + invert and ' (inverted)' or '', color_summary, matched_lines, color_reset), + buffer) + # print last lines + if matched_lines.get_matches_count(): + if count: + # with count we sort by matches lines instead of just lines. + matched_lines_items = matched_lines.items_count() + else: + matched_lines_items = matched_lines.items() + + matched_lines.get_last_lines(max_lines) + for log, lines in matched_lines_items: + if lines.matches_count: + # matched lines + if not count: + # print lines + weechat_format = True + if exact: + lines.onlyUniq() + for line in lines: + #debug(repr(line)) + if line == linesList._sep: + # separator + prnt(buffer, context_sep) + else: + if '\x00' in line: + # log was corrupted + error("Found garbage in log '%s', maybe it's corrupted" %log) + line = line.replace('\x00', '') + prnt_date_tags(buffer, 0, 'no_highlight', format_line(line)) + + # summary + if count or get_config_boolean('show_summary'): + summary = make_summary(log, lines) + print_line(summary, buffer) + + # separator + if not count and lines: + prnt(buffer, '\n') + else: + print_line('No matches found.', buffer) + + # set title + global time_start + time_end = now() + # total time + time_total = time_end - time_start + # percent of the total time used for grepping + time_grep_pct = (time_grep - time_start)/time_total*100 + #debug('time: %.4f seconds (%.2f%%)' %(time_total, time_grep_pct)) + if not count and len_total_lines > max_lines: + note = ' (last %s lines shown)' %len(matched_lines) + else: + note = '' + title = "Search in %s%s%s %s matches%s | pattern \"%s%s%s\"%s %s | %.4f seconds (%.2f%%)" \ + %(color_title, matched_lines, color_reset, matched_lines.get_matches_count(), note, + color_title, pattern_tmpl, color_reset, invert and ' (inverted)' or '', format_options(), + time_total, time_grep_pct) + weechat.buffer_set(buffer, 'title', title) + + if get_config_boolean('go_to_buffer'): + weechat.buffer_set(buffer, 'display', '1') + + # free matched_lines so it can be removed from memory + del matched_lines + +def split_line(s): + """Splits log's line 's' in 3 parts, date, nick and msg.""" + global weechat_format + if weechat_format and s.count('\t') >= 2: + date, nick, msg = s.split('\t', 2) # date, nick, message + else: + # looks like log isn't in weechat's format + weechat_format = False # incoming lines won't be formatted + date, nick, msg = '', '', s + # remove tabs + if '\t' in msg: + msg = msg.replace('\t', ' ') + return date, nick, msg + +def print_line(s, buffer=None, display=False): + """Prints 's' in script's buffer as 'script_nick'. For displaying search summaries.""" + if buffer is None: + buffer = buffer_create() + say('%s%s' %(color_info, s), buffer) + if display and get_config_boolean('go_to_buffer'): + weechat.buffer_set(buffer, 'display', '1') + +def format_options(): + global matchcase, number, count, exact, hilight, invert + global tail, head, after_context, before_context + options = [] + append = options.append + insert = options.insert + chars = 'cHmov' + for i, flag in enumerate((count, hilight, matchcase, exact, invert)): + if flag: + append(chars[i]) + + if head or tail: + n = get_config_int('default_tail_head') + if head: + append('h') + if head != n: + insert(-1, ' -') + append('n') + append(head) + elif tail: + append('t') + if tail != n: + insert(-1, ' -') + append('n') + append(tail) + + if before_context and after_context and (before_context == after_context): + append(' -C') + append(before_context) + else: + if before_context: + append(' -B') + append(before_context) + if after_context: + append(' -A') + append(after_context) + + s = ''.join(map(str, options)).strip() + if s and s[0] != '-': + s = '-' + s + return s + +def buffer_create(title=None): + """Returns our buffer pointer, creates and cleans the buffer if needed.""" + buffer = weechat.buffer_search('python', SCRIPT_NAME) + if not buffer: + buffer = weechat.buffer_new(SCRIPT_NAME, 'buffer_input', '', '', '') + weechat.buffer_set(buffer, 'time_for_each_line', '0') + weechat.buffer_set(buffer, 'nicklist', '0') + weechat.buffer_set(buffer, 'title', title or 'grep output buffer') + weechat.buffer_set(buffer, 'localvar_set_no_log', '1') + elif title: + weechat.buffer_set(buffer, 'title', title) + return buffer + +def buffer_input(data, buffer, input_data): + """Repeats last search with 'input_data' as regexp.""" + try: + cmd_grep_stop(buffer, input_data) + except: + return WEECHAT_RC_OK + + global search_in_buffers, search_in_files + global pattern + try: + if pattern and (search_in_files or search_in_buffers): + # check if the buffer pointers are still valid + for pointer in search_in_buffers: + infolist = weechat.infolist_get('buffer', pointer, '') + if not infolist: + del search_in_buffers[search_in_buffers.index(pointer)] + weechat.infolist_free(infolist) + try: + cmd_grep_parsing(input_data) + except Exception, e: + error('Argument error, %s' %e, buffer=buffer) + return WEECHAT_RC_OK + try: + show_matching_lines() + except Exception, e: + error(e) + except NameError: + error("There isn't any previous search to repeat.", buffer=buffer) + return WEECHAT_RC_OK + +### Commands ### +def cmd_init(): + """Resets global vars.""" + global home_dir, cache_dir, nick_dict + global pattern_tmpl, pattern, matchcase, number, count, exact, hilight, invert + global tail, head, after_context, before_context + hilight = '' + head = tail = after_context = before_context = invert = False + matchcase = count = exact = False + pattern_tmpl = pattern = number = None + home_dir = get_home() + cache_dir = {} # for avoid walking the dir tree more than once per command + nick_dict = {} # nick cache for don't calculate nick color every time + +def cmd_grep_parsing(args): + """Parses args for /grep and grep input buffer.""" + global pattern_tmpl, pattern, matchcase, number, count, exact, hilight, invert + global tail, head, after_context, before_context + global log_name, buffer_name, only_buffers, all + opts, args = getopt.gnu_getopt(args.split(), 'cmHeahtivn:bA:B:C:o', ['count', 'matchcase', 'hilight', + 'exact', 'all', 'head', 'tail', 'number=', 'buffer', 'after-context=', 'before-context=', + 'context=', 'invert', 'only-match']) + #debug(opts, 'opts: '); debug(args, 'args: ') + if len(args) >= 2: + if args[0] == 'log': + del args[0] + log_name = args.pop(0) + elif args[0] == 'buffer': + del args[0] + buffer_name = args.pop(0) + + def tmplReplacer(match): + """This function will replace templates with regexps""" + s = match.groups()[0] + tmpl_args = s.split() + tmpl_key, _, tmpl_args = s.partition(' ') + try: + template = templates[tmpl_key] + if callable(template): + r = template(tmpl_args) + if not r: + error("Template %s returned empty string "\ + "(WeeChat doesn't have enough data)." %t) + return r + else: + return template + except: + return t + + args = ' '.join(args) # join pattern for keep spaces + if args: + pattern_tmpl = args + pattern = _tmplRe.sub(tmplReplacer, args) + debug('Using regexp: %s', pattern) + if not pattern: + raise Exception, 'No pattern for grep the logs.' + + def positive_number(opt, val): + try: + number = int(val) + if number < 0: + raise ValueError + return number + except ValueError: + if len(opt) == 1: + opt = '-' + opt + else: + opt = '--' + opt + raise Exception, "argument for %s must be a positive integer." %opt + + for opt, val in opts: + opt = opt.strip('-') + if opt in ('c', 'count'): + count = not count + elif opt in ('m', 'matchcase'): + matchcase = not matchcase + elif opt in ('H', 'hilight'): + # hilight must be always a string! + if hilight: + hilight = '' + else: + hilight = '%s,%s' %(color_hilight, color_reset) + # we pass the colors in the variable itself because check_string() must not use + # weechat's module when applying the colors (this is for grep in a hooked process) + elif opt in ('e', 'exact', 'o', 'only-match'): + exact = not exact + invert = False + elif opt in ('a', 'all'): + all = not all + elif opt in ('h', 'head'): + head = not head + tail = False + elif opt in ('t', 'tail'): + tail = not tail + head = False + elif opt in ('b', 'buffer'): + only_buffers = True + elif opt in ('n', 'number'): + number = positive_number(opt, val) + elif opt in ('C', 'context'): + n = positive_number(opt, val) + after_context = n + before_context = n + elif opt in ('A', 'after-context'): + after_context = positive_number(opt, val) + elif opt in ('B', 'before-context'): + before_context = positive_number(opt, val) + elif opt in ('i', 'v', 'invert'): + invert = not invert + exact = False + # number check + if number is not None: + if number == 0: + head = tail = False + number = None + elif head: + head = number + elif tail: + tail = number + else: + n = get_config_int('default_tail_head') + if head: + head = n + elif tail: + tail = n + +def cmd_grep_stop(buffer, args): + global hook_file_grep, pattern, matched_lines, tmpFile + if hook_file_grep: + if args == 'stop': + weechat.unhook(hook_file_grep) + hook_file_grep = None + s = 'Search for \'%s\' stopped.' %pattern + say(s, buffer) + grep_buffer = weechat.buffer_search('python', SCRIPT_NAME) + if grep_buffer: + weechat.buffer_set(grep_buffer, 'title', s) + del matched_lines + tmpFile = None + else: + say(get_grep_file_status(), buffer) + raise Exception + +def cmd_grep(data, buffer, args): + """Search in buffers and logs.""" + global pattern, matchcase, head, tail, number, count, exact, hilight + try: + cmd_grep_stop(buffer, args) + except: + return WEECHAT_RC_OK + + if not args: + weechat.command('', '/help %s' %SCRIPT_COMMAND) + return WEECHAT_RC_OK + + cmd_init() + global log_name, buffer_name, only_buffers, all + log_name = buffer_name = '' + only_buffers = all = False + + # parse + try: + cmd_grep_parsing(args) + except Exception, e: + error('Argument error, %s' %e) + return WEECHAT_RC_OK + + # find logs + log_file = search_buffer = None + if log_name: + log_file = get_file_by_pattern(log_name, all) + if not log_file: + error("Couldn't find any log for %s. Try /logs" %log_name) + return WEECHAT_RC_OK + elif all: + search_buffer = get_all_buffers() + elif buffer_name: + search_buffer = get_buffer_by_name(buffer_name) + if not search_buffer: + # there's no buffer, try in the logs + log_file = get_file_by_name(buffer_name) + if not log_file: + error("Logs or buffer for '%s' not found." %buffer_name) + return WEECHAT_RC_OK + else: + search_buffer = [search_buffer] + else: + search_buffer = [buffer] + + # make the log list + global search_in_files, search_in_buffers + search_in_files = [] + search_in_buffers = [] + if log_file: + search_in_files = log_file + elif not only_buffers: + #debug(search_buffer) + for pointer in search_buffer: + log = get_file_by_buffer(pointer) + #debug('buffer %s log %s' %(pointer, log)) + if log: + search_in_files.append(log) + else: + search_in_buffers.append(pointer) + else: + search_in_buffers = search_buffer + + # grepping + try: + show_matching_lines() + except Exception, e: + error(e) + return WEECHAT_RC_OK + +def cmd_logs(data, buffer, args): + """List files in Weechat's log dir.""" + cmd_init() + global home_dir + sort_by_size = False + filter = [] + + try: + opts, args = getopt.gnu_getopt(args.split(), 's', ['size']) + if args: + filter = args + for opt, var in opts: + opt = opt.strip('-') + if opt in ('size', 's'): + sort_by_size = True + except Exception, e: + error('Argument error, %s' %e) + return WEECHAT_RC_OK + + # is there's a filter, filter_excludes should be False + file_list = dir_list(home_dir, filter, filter_excludes=not filter) + if sort_by_size: + file_list.sort(key=get_size) + else: + file_list.sort() + + file_sizes = map(lambda x: human_readable_size(get_size(x)), file_list) + # calculate column lenght + if file_list: + L = file_list[:] + L.sort(key=len) + bigest = L[-1] + column_len = len(bigest) + 3 + else: + column_len = '' + + buffer = buffer_create() + if get_config_boolean('clear_buffer'): + weechat.buffer_clear(buffer) + file_list = zip(file_list, file_sizes) + msg = 'Found %s logs.' %len(file_list) + + print_line(msg, buffer, display=True) + for file, size in file_list: + separator = column_len and '.'*(column_len - len(file)) + prnt(buffer, '%s %s %s' %(strip_home(file), separator, size)) + if file_list: + print_line(msg, buffer) + return WEECHAT_RC_OK + + +### Completion ### +def completion_log_files(data, completion_item, buffer, completion): + #debug('completion: %s' %', '.join((data, completion_item, buffer, completion))) + global home_dir + l = len(home_dir) + completion_list_add = weechat.hook_completion_list_add + WEECHAT_LIST_POS_END = weechat.WEECHAT_LIST_POS_END + for log in dir_list(home_dir): + completion_list_add(completion, log[l:], 0, WEECHAT_LIST_POS_END) + return WEECHAT_RC_OK + +def completion_grep_args(data, completion_item, buffer, completion): + for arg in ('count', 'all', 'matchcase', 'hilight', 'exact', 'head', 'tail', 'number', 'buffer', + 'after-context', 'before-context', 'context', 'invert', 'only-match'): + weechat.hook_completion_list_add(completion, '--' + arg, 0, weechat.WEECHAT_LIST_POS_SORT) + for tmpl in templates: + weechat.hook_completion_list_add(completion, '%{' + tmpl, 0, weechat.WEECHAT_LIST_POS_SORT) + return WEECHAT_RC_OK + + +### Templates ### +# template placeholder +_tmplRe = re.compile(r'%\{(\w+.*?)(?:\}|$)') +# will match 999.999.999.999 but I don't care +ipAddress = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' +domain = r'[\w-]{2,}(?:\.[\w-]{2,})*\.[a-z]{2,}' +url = r'\w+://(?:%s|%s)(?::\d+)?(?:/[^\])>\s]*)?' % (domain, ipAddress) + +def make_url_regexp(args): + #debug('make url: %s', args) + if args: + words = r'(?:%s)' %'|'.join(map(re.escape, args.split())) + return r'(?:\w+://|www\.)[^\s]*%s[^\s]*(?:/[^\])>\s]*)?' %words + else: + return url + +def make_simple_regexp(pattern): + s = '' + for c in pattern: + if c == '*': + s += '.*' + elif c == '?': + s += '.' + else: + s += re.escape(c) + return s + +templates = { + 'ip': ipAddress, + 'url': make_url_regexp, + 'escape': lambda s: re.escape(s), + 'simple': make_simple_regexp, + 'domain': domain, + } + +### Main ### +def delete_bytecode(): + global script_path + bytecode = path.join(script_path, SCRIPT_NAME + '.pyc') + if path.isfile(bytecode): + os.remove(bytecode) + return WEECHAT_RC_OK + +if __name__ == '__main__' and import_ok and \ + weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, \ + SCRIPT_DESC, 'delete_bytecode', ''): + home_dir = get_home() + + # for import ourselves + global script_path + script_path = path.dirname(__file__) + sys.path.append(script_path) + delete_bytecode() + + # check python version + import sys + global bytecode + if sys.version_info > (2, 6): + bytecode = 'B' + else: + bytecode = '' + + + weechat.hook_command(SCRIPT_COMMAND, cmd_grep.__doc__, + "[log | buffer | stop] [-a|--all] [-b|--buffer] [-c|--count] [-m|--matchcase] " + "[-H|--hilight] [-o|--only-match] [-i|-v|--invert] [(-h|--head)|(-t|--tail) [-n|--number ]] " + "[-A|--after-context ] [-B|--before-context ] [-C|--context ] ", +# help +""" + log : Search in one log that matches in the logger path. + Use '*' and '?' as wildcards. + buffer : Search in buffer , if there's no buffer with it will + try to search for a log file. + stop: Stops a currently running search. + -a --all: Search in all open buffers. + If used with 'log ' search in all logs that matches . + -b --buffer: Search only in buffers, not in file logs. + -c --count: Just count the number of matched lines instead of showing them. + -m --matchcase: Don't do case insensible search. + -H --hilight: Colour exact matches in output buffer. +-o --only-match: Print only the matching part of the line (unique matches). + -v -i --invert: Print lines that don't match the regular expression. + -t --tail: Print the last 10 matching lines. + -h --head: Print the first 10 matching lines. +-n --number : Overrides default number of lines for --tail or --head. +-A --after-context : Shows lines of trailing context after matching lines. +-B --before-context : Shows lines of leading context before matching lines. +-C --context : Same as using both --after-context and --before-context simultaneously. + : Expression to search. + +Grep buffer: + Input line accepts most arguments of /grep, it'll repeat last search using the new + arguments provided. You can't search in different logs from the buffer's input. + Boolean arguments like --count, --tail, --head, --hilight, ... are toggleable + +Python regular expression syntax: + See http://docs.python.org/lib/re-syntax.html + +Grep Templates: + %{url [text]}: Matches anything like an url, or an url with text. + %{ip}: Matches anything that looks like an ip. + %{domain}: Matches anything like a domain. + %{escape text}: Escapes text in pattern. + %{simple pattern}: Converts a pattern with '*' and '?' wildcards into a regexp. + +Examples: + Search for urls with the word 'weechat' said by 'nick' + /grep nick\\t.*%{url weechat} + Search for '*.*' string + /grep %{escape *.*} +""", + # completion template + "buffer %(buffers_names) %(grep_arguments)|%*" + "||log %(grep_log_files) %(grep_arguments)|%*" + "||stop" + "||%(grep_arguments)|%*", + 'cmd_grep' ,'') + weechat.hook_command('logs', cmd_logs.__doc__, "[-s|--size] []", + "-s --size: Sort logs by size.\n" + " : Only show logs that match . Use '*' and '?' as wildcards.", '--size', 'cmd_logs', '') + + weechat.hook_completion('grep_log_files', "list of log files", + 'completion_log_files', '') + weechat.hook_completion('grep_arguments', "list of arguments", + 'completion_grep_args', '') + + # settings + for opt, val in settings.iteritems(): + if not weechat.config_is_set_plugin(opt): + weechat.config_set_plugin(opt, val) + + # colors + color_date = weechat.color('brown') + color_info = weechat.color('cyan') + color_hilight = weechat.color('lightred') + color_reset = weechat.color('reset') + color_title = weechat.color('yellow') + color_summary = weechat.color('lightcyan') + color_delimiter = weechat.color('chat_delimiters') + color_script_nick = weechat.color('chat_nick') + + # pretty [grep] + script_nick = '%s[%s%s%s]%s' %(color_delimiter, color_script_nick, SCRIPT_NAME, color_delimiter, + color_reset) + script_nick_nocolor = '[%s]' %SCRIPT_NAME + # paragraph separator when using context options + context_sep = '%s\t%s--' %(script_nick, color_info) + + # ------------------------------------------------------------------------- + # Debug + + if weechat.config_get_plugin('debug'): + try: + # custom debug module I use, allows me to inspect script's objects. + import pybuffer + debug = pybuffer.debugBuffer(globals(), '%s_debug' % SCRIPT_NAME) + except: + def debug(s, *args): + if not isinstance(s, basestring): + s = str(s) + if args: + s = s %args + prnt('', '%s\t%s' %(script_nick, s)) + else: + def debug(*args): + pass + +# vim:set shiftwidth=4 tabstop=4 softtabstop=4 expandtab textwidth=100: diff --git a/weechat/relay.conf b/weechat/relay.conf index 019f72e..dbd6b8c 100644 --- a/weechat/relay.conf +++ b/weechat/relay.conf @@ -1,5 +1,5 @@ # -# relay.conf -- weechat v1.0.1 +# relay.conf -- weechat v1.1 # [look] @@ -26,6 +26,7 @@ ipv6 = on max_clients = 5 password = "" ssl_cert_key = "%h/ssl/relay.pem" +ssl_priorities = "NORMAL:-VERS-SSL3.0" websocket_allowed_origins = "" [irc] diff --git a/weechat/script.conf b/weechat/script.conf index a0fe570..59fc23a 100644 --- a/weechat/script.conf +++ b/weechat/script.conf @@ -1,5 +1,5 @@ # -# script.conf -- weechat v1.0.1 +# script.conf -- weechat v1.1 # [look] @@ -46,3 +46,4 @@ cache_expire = 60 dir = "%h/script" hold = "" url = "http://www.weechat.org/files/plugins.xml.gz" +url_force_https = on diff --git a/weechat/sec.conf b/weechat/sec.conf index c8a08d8..899f2a1 100644 --- a/weechat/sec.conf +++ b/weechat/sec.conf @@ -1,5 +1,5 @@ # -# sec.conf -- weechat v1.0.1 +# sec.conf -- weechat v1.1 # [crypt] diff --git a/weechat/trigger.conf b/weechat/trigger.conf index 3131ea2..da31567 100644 --- a/weechat/trigger.conf +++ b/weechat/trigger.conf @@ -1,5 +1,5 @@ # -# trigger.conf -- weechat v1.0.1 +# trigger.conf -- weechat v1.1 # [look] diff --git a/weechat/weechat.conf b/weechat/weechat.conf index 25f7fa8..a3d6288 100644 --- a/weechat/weechat.conf +++ b/weechat/weechat.conf @@ -1,5 +1,5 @@ # -# weechat.conf -- weechat v1.0.1 +# weechat.conf -- weechat v1.1 # [debug] @@ -38,6 +38,7 @@ color_nick_offline = on color_pairs_auto_reset = 5 color_real_white = off command_chars = "" +command_incomplete = off confirm_quit = off day_change = off day_change_message_1date = "-- %a, %d %b %Y --" @@ -67,6 +68,7 @@ input_share_overwrite = off input_undo_max = 32 item_buffer_filter = "•" item_buffer_zoom = "!" +item_mouse_status = "M" item_time_format = "%H:%M" jump_current_to_previous_buffer = on jump_previous_buffer_when_closing = on @@ -173,6 +175,7 @@ status_data_other = default status_data_private = 121 status_filter = green status_more = 229 +status_mouse = green status_name = 121 status_name_ssl = 121 status_nicklist_count = default @@ -181,6 +184,7 @@ status_time = default [completion] base_word_until_cursor = on +command_inline = off default_template = "%(nicks)|%(irc_channels)" nick_add_space = on nick_completer = ":" diff --git a/weechat/xfer.conf b/weechat/xfer.conf index 6e78f2a..43ec7b2 100644 --- a/weechat/xfer.conf +++ b/weechat/xfer.conf @@ -1,5 +1,5 @@ # -# xfer.conf -- weechat v1.0.1 +# xfer.conf -- weechat v1.1 # [look]