notiffany 0.0.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/notiffany/notifier.rb +42 -37
- data/lib/notiffany/notifier/base.rb +1 -1
- data/lib/notiffany/notifier/config.rb +34 -0
- data/lib/notiffany/notifier/detected.rb +14 -8
- data/lib/notiffany/notifier/emacs.rb +26 -36
- data/lib/notiffany/notifier/emacs/client.rb +52 -0
- data/lib/notiffany/notifier/file.rb +2 -2
- data/lib/notiffany/notifier/gntp.rb +3 -2
- data/lib/notiffany/notifier/notifysend.rb +2 -2
- data/lib/notiffany/notifier/terminal_title.rb +1 -1
- data/lib/notiffany/notifier/tmux.rb +21 -244
- data/lib/notiffany/notifier/tmux/client.rb +103 -0
- data/lib/notiffany/notifier/tmux/notification.rb +62 -0
- data/lib/notiffany/notifier/tmux/session.rb +40 -0
- data/lib/notiffany/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 107a426a3f017b084ea3a11ac5a3c951b8569269
|
4
|
+
data.tar.gz: f4f275c620a69ff487e61b936cadfd2b1eebcbac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 394ec7473db4997eaae759be74f386dc9b2acf4a65d60a9fb3196a6a817a7a21803330952701dee5a1327b7db52b30bc4f2fc9722d1320b5199c4e87bdd5b44d
|
7
|
+
data.tar.gz: d89a0a76ee60251e5b7c2efd089fa902b0f3974db6637e48d72b88e8b112f045311525415e24da1019783c14e561ec84f34afd78a7a72f7de8dcac2305f72ba0
|
data/README.md
CHANGED
data/lib/notiffany/notifier.rb
CHANGED
@@ -2,9 +2,9 @@ require "yaml"
|
|
2
2
|
require "rbconfig"
|
3
3
|
require "pathname"
|
4
4
|
require "nenv"
|
5
|
-
require "logger"
|
6
5
|
|
7
6
|
require "notiffany/notifier/detected"
|
7
|
+
require "notiffany/notifier/config"
|
8
8
|
|
9
9
|
module Notiffany
|
10
10
|
# The notifier handles sending messages to different notifiers. Currently the
|
@@ -43,9 +43,7 @@ module Notiffany
|
|
43
43
|
end
|
44
44
|
|
45
45
|
class Notifier
|
46
|
-
|
47
|
-
|
48
|
-
NOTIFICATIONS_DISABLED = "Notifications disabled by GUARD_NOTIFY" +
|
46
|
+
NOTIFICATIONS_DISABLED = "Notifications disabled by GUARD_NOTIFY" \
|
49
47
|
" environment variable"
|
50
48
|
|
51
49
|
USING_NOTIFIER = "Notiffany is using %s to send notifications."
|
@@ -79,35 +77,16 @@ module Notiffany
|
|
79
77
|
class NotServer < RuntimeError
|
80
78
|
end
|
81
79
|
|
82
|
-
|
83
|
-
@env_namespace = opts.fetch(:namespace, "notiffany")
|
84
|
-
@logger = opts.fetch(:logger) do
|
85
|
-
Logger.new($stderr).tap { |l| l.level = Logger::WARN }
|
86
|
-
end
|
80
|
+
attr_reader :config
|
87
81
|
|
88
|
-
|
89
|
-
@
|
82
|
+
def initialize(opts)
|
83
|
+
@config = Config.new(opts)
|
84
|
+
@detected = Detected.new(SUPPORTED, config.env_namespace, config.logger)
|
90
85
|
return if _client?
|
91
86
|
|
92
|
-
|
93
|
-
|
94
|
-
fail "Already connected" if active?
|
95
|
-
|
96
|
-
options = DEFAULTS.merge(opts)
|
97
|
-
return unless enabled? && options[:notify]
|
98
|
-
|
99
|
-
notifiers = opts.fetch(:notifiers, {})
|
100
|
-
if notifiers.any?
|
101
|
-
notifiers.each do |name, notifier_options|
|
102
|
-
@detected.add(name, notifier_options)
|
103
|
-
end
|
104
|
-
else
|
105
|
-
@detected.detect
|
106
|
-
end
|
107
|
-
|
108
|
-
turn_on
|
87
|
+
_activate
|
109
88
|
rescue Detected::NoneAvailableError => e
|
110
|
-
|
89
|
+
config.logger.info e.to_s
|
111
90
|
end
|
112
91
|
|
113
92
|
def disconnect
|
@@ -133,13 +112,7 @@ module Notiffany
|
|
133
112
|
|
134
113
|
fail "Already active!" if active?
|
135
114
|
|
136
|
-
|
137
|
-
|
138
|
-
@detected.available.each do |obj|
|
139
|
-
@logger.debug(format(USING_NOTIFIER, obj.title)) unless silent
|
140
|
-
obj.turn_on if obj.respond_to?(:turn_on)
|
141
|
-
end
|
142
|
-
|
115
|
+
_turn_on_notifiers(options)
|
143
116
|
_env.notify_active = true
|
144
117
|
end
|
145
118
|
|
@@ -191,7 +164,7 @@ module Notiffany
|
|
191
164
|
private
|
192
165
|
|
193
166
|
def _env
|
194
|
-
@environment ||= Env.new(
|
167
|
+
@environment ||= Env.new(config.env_namespace)
|
195
168
|
end
|
196
169
|
|
197
170
|
def _check_server!
|
@@ -201,5 +174,37 @@ module Notiffany
|
|
201
174
|
def _client?
|
202
175
|
(pid = _env.notify_pid) && (pid != $$)
|
203
176
|
end
|
177
|
+
|
178
|
+
def _detect_or_add_notifiers
|
179
|
+
notifiers = config.notifiers
|
180
|
+
return @detected.detect if notifiers.empty?
|
181
|
+
|
182
|
+
notifiers.each do |name, notifier_options|
|
183
|
+
@detected.add(name, notifier_options)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def _notification_wanted?
|
188
|
+
enabled? && config.notify?
|
189
|
+
end
|
190
|
+
|
191
|
+
def _activate
|
192
|
+
_env.notify_pid = $$
|
193
|
+
|
194
|
+
fail "Already connected" if active?
|
195
|
+
|
196
|
+
return unless _notification_wanted?
|
197
|
+
|
198
|
+
_detect_or_add_notifiers
|
199
|
+
turn_on
|
200
|
+
end
|
201
|
+
|
202
|
+
def _turn_on_notifiers(options)
|
203
|
+
silent = options[:silent]
|
204
|
+
@detected.available.each do |obj|
|
205
|
+
config.logger.debug(format(USING_NOTIFIER, obj.title)) unless silent
|
206
|
+
obj.turn_on if obj.respond_to?(:turn_on)
|
207
|
+
end
|
208
|
+
end
|
204
209
|
end
|
205
210
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
# Configuration class for Notifier
|
6
|
+
class Config
|
7
|
+
DEFAULTS = { notify: true }.freeze
|
8
|
+
|
9
|
+
attr_reader :env_namespace
|
10
|
+
attr_reader :logger
|
11
|
+
attr_reader :notifiers
|
12
|
+
|
13
|
+
def initialize(opts)
|
14
|
+
options = DEFAULTS.merge(opts)
|
15
|
+
@env_namespace = opts.fetch(:namespace, "notiffany")
|
16
|
+
@logger = _setup_logger(options)
|
17
|
+
@notify = options[:notify]
|
18
|
+
@notifiers = opts.fetch(:notifiers, {})
|
19
|
+
end
|
20
|
+
|
21
|
+
def notify?
|
22
|
+
@notify
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def _setup_logger(opts)
|
28
|
+
opts.fetch(:logger) do
|
29
|
+
Logger.new($stderr).tap { |l| l.level = Logger::WARN }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -19,8 +19,8 @@ module Notiffany
|
|
19
19
|
# TODO: use a socket instead of passing env variables to child processes
|
20
20
|
# (currently probably only used by guard-cucumber anyway)
|
21
21
|
YamlEnvStorage = Nenv::Builder.build do
|
22
|
-
create_method(:notifiers=) { |data| YAML
|
23
|
-
create_method(:notifiers) { |data| data ? YAML
|
22
|
+
create_method(:notifiers=) { |data| YAML.dump(data || []) }
|
23
|
+
create_method(:notifiers) { |data| data ? YAML.load(data) : [] }
|
24
24
|
end
|
25
25
|
|
26
26
|
# @private api
|
@@ -37,9 +37,7 @@ module Notiffany
|
|
37
37
|
@name = name
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
@name
|
42
|
-
end
|
40
|
+
attr_reader :name
|
43
41
|
|
44
42
|
def message
|
45
43
|
"Unknown notifier: #{@name.inspect}"
|
@@ -61,7 +59,7 @@ module Notiffany
|
|
61
59
|
@supported.each do |group|
|
62
60
|
group.detect do |name, _|
|
63
61
|
begin
|
64
|
-
|
62
|
+
_add(name, {})
|
65
63
|
true
|
66
64
|
rescue Notifier::Base::UnavailableError => e
|
67
65
|
@logger.debug "Notiffany: #{name} not available (#{e.message})."
|
@@ -79,7 +77,17 @@ module Notiffany
|
|
79
77
|
end
|
80
78
|
end
|
81
79
|
|
80
|
+
# Called when user has notifier-specific config.
|
81
|
+
# Honor the config by warning if something is wrong
|
82
82
|
def add(name, opts)
|
83
|
+
_add(name, opts)
|
84
|
+
rescue Notifier::Base::UnavailableError => e
|
85
|
+
@logger.warning("Notiffany: #{name} not available (#{e.message}).")
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def _add(name, opts)
|
83
91
|
@available = nil
|
84
92
|
all = _notifiers
|
85
93
|
|
@@ -98,8 +106,6 @@ module Notiffany
|
|
98
106
|
all.each { |item| item[:options] = opts if item[:name] == name }
|
99
107
|
end
|
100
108
|
|
101
|
-
private
|
102
|
-
|
103
109
|
def _to_module(name)
|
104
110
|
@supported.each do |group|
|
105
111
|
next unless (notifier = group.detect { |n, _| n == name })
|
@@ -1,5 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'notiffany/notifier/base'
|
2
|
+
require 'shellany/sheller'
|
3
|
+
|
4
|
+
require 'notiffany/notifier/emacs/client'
|
3
5
|
|
4
6
|
module Notiffany
|
5
7
|
class Notifier
|
@@ -8,37 +10,18 @@ module Notiffany
|
|
8
10
|
#
|
9
11
|
class Emacs < Base
|
10
12
|
DEFAULTS = {
|
11
|
-
client:
|
12
|
-
success:
|
13
|
-
failed:
|
14
|
-
default:
|
15
|
-
fontcolor:
|
16
|
-
}
|
17
|
-
|
18
|
-
class Client
|
19
|
-
def initialize(options)
|
20
|
-
@client = options[:client]
|
21
|
-
end
|
22
|
-
|
23
|
-
def available?
|
24
|
-
emacs_eval({ 'ALTERNATE_EDITOR' =>'false' }, "'1'")
|
25
|
-
end
|
13
|
+
client: 'emacsclient',
|
14
|
+
success: 'ForestGreen',
|
15
|
+
failed: 'Firebrick',
|
16
|
+
default: 'Black',
|
17
|
+
fontcolor: 'White'
|
18
|
+
}.freeze
|
26
19
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
EOF
|
33
|
-
emacs_eval(elisp)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def emacs_eval(env={}, code)
|
39
|
-
Shellany::Sheller.run(env, @client, "--eval", code)
|
40
|
-
end
|
41
|
-
end
|
20
|
+
DEFAULT_ELISP_ERB = <<EOF.freeze
|
21
|
+
(set-face-attribute 'mode-line nil
|
22
|
+
:background "<%= bgcolor %>"
|
23
|
+
:foreground "<%= color %>")
|
24
|
+
EOF
|
42
25
|
|
43
26
|
private
|
44
27
|
|
@@ -47,8 +30,8 @@ module Notiffany
|
|
47
30
|
end
|
48
31
|
|
49
32
|
def _check_available(options)
|
50
|
-
return if Client.new(options).available?
|
51
|
-
|
33
|
+
return if Client.new(options.merge(elisp_erb: "'1'")).available?
|
34
|
+
raise UnavailableError, 'Emacs client failed'
|
52
35
|
end
|
53
36
|
|
54
37
|
# Shows a system notification.
|
@@ -72,10 +55,12 @@ module Notiffany
|
|
72
55
|
# @option opts [String, Integer] priority specify an int or named key
|
73
56
|
# (default is 0)
|
74
57
|
#
|
75
|
-
def _perform_notify(
|
58
|
+
def _perform_notify(message, opts = {})
|
76
59
|
color = _emacs_color(opts[:type], opts)
|
77
60
|
fontcolor = _emacs_color(:fontcolor, opts)
|
78
|
-
|
61
|
+
|
62
|
+
opts = opts.merge(elisp_erb: _erb_for(opts[:elisp_file]))
|
63
|
+
Client.new(opts).notify(fontcolor, color, message)
|
79
64
|
end
|
80
65
|
|
81
66
|
# Get the Emacs color for the notification type.
|
@@ -102,6 +87,11 @@ module Notiffany
|
|
102
87
|
default = options.fetch(:default, DEFAULTS[:default])
|
103
88
|
options.fetch(type.to_sym, default)
|
104
89
|
end
|
90
|
+
|
91
|
+
def _erb_for(filename)
|
92
|
+
return DEFAULT_ELISP_ERB unless filename
|
93
|
+
IO.read(::File.expand_path(filename))
|
94
|
+
end
|
105
95
|
end
|
106
96
|
end
|
107
97
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'erb'
|
2
|
+
module Notiffany
|
3
|
+
class Notifier
|
4
|
+
class Emacs < Base
|
5
|
+
# Handles evaluating ELISP code in Emacs via Erb
|
6
|
+
class Client
|
7
|
+
attr_reader :elisp_erb
|
8
|
+
|
9
|
+
# Creates a safe binding with local variables for ERB
|
10
|
+
class Elisp < ERB
|
11
|
+
attr_reader :color
|
12
|
+
attr_reader :bgcolor
|
13
|
+
attr_reader :message
|
14
|
+
|
15
|
+
def initialize(code, color, bgcolor, message)
|
16
|
+
@color = color
|
17
|
+
@bgcolor = bgcolor
|
18
|
+
@message = message
|
19
|
+
@code = code
|
20
|
+
super(@code)
|
21
|
+
end
|
22
|
+
|
23
|
+
def result
|
24
|
+
super(binding)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(options)
|
29
|
+
@client = options[:client]
|
30
|
+
@elisp_erb = options[:elisp_erb]
|
31
|
+
raise ArgumentError, 'No :elisp_erb option given!' unless elisp_erb
|
32
|
+
end
|
33
|
+
|
34
|
+
def available?
|
35
|
+
script = Elisp.new(@elisp_erb, nil, nil, nil).result
|
36
|
+
_emacs_eval({ 'ALTERNATE_EDITOR' => 'false' }, script)
|
37
|
+
end
|
38
|
+
|
39
|
+
def notify(color, bgcolor, message = nil)
|
40
|
+
elisp = Elisp.new(elisp_erb, color, bgcolor, message).result
|
41
|
+
_emacs_eval({ 'ALTERNATE_EDITOR' => 'false' }, elisp)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def _emacs_eval(env, code)
|
47
|
+
Shellany::Sheller.run(env, @client, '--eval', code)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -32,8 +32,8 @@ module Notiffany
|
|
32
32
|
def _perform_notify(message, opts = {})
|
33
33
|
fail UnavailableError, "No :path option given" unless opts[:path]
|
34
34
|
|
35
|
-
|
36
|
-
::File.write(opts[:path],
|
35
|
+
str = format(opts[:format], opts[:type], opts[:title], message)
|
36
|
+
::File.write(opts[:path], str)
|
37
37
|
end
|
38
38
|
|
39
39
|
def _gem_name
|
@@ -24,11 +24,12 @@ module Notiffany
|
|
24
24
|
CLIENT_DEFAULTS = {
|
25
25
|
host: "127.0.0.1",
|
26
26
|
password: "",
|
27
|
-
port:
|
27
|
+
port: 23_053
|
28
28
|
}
|
29
29
|
|
30
30
|
def _supported_hosts
|
31
|
-
%w(darwin linux linux-gnu freebsd openbsd sunos solaris mswin mingw
|
31
|
+
%w(darwin linux linux-gnu freebsd openbsd sunos solaris mswin mingw
|
32
|
+
cygwin)
|
32
33
|
end
|
33
34
|
|
34
35
|
def _gem_name
|
@@ -26,7 +26,7 @@ module Notiffany
|
|
26
26
|
def _gem_name
|
27
27
|
nil
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def _supported_hosts
|
31
31
|
%w(linux linux-gnu freebsd openbsd sunos solaris)
|
32
32
|
end
|
@@ -81,7 +81,7 @@ module Notiffany
|
|
81
81
|
#
|
82
82
|
def _to_arguments(command, supported, opts = {})
|
83
83
|
opts.inject(command) do |cmd, (flag, value)|
|
84
|
-
supported.include?(flag) ? (cmd << "-#{
|
84
|
+
supported.include?(flag) ? (cmd << "-#{flag}" << value.to_s) : cmd
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
require "notiffany/notifier/base"
|
2
|
-
|
2
|
+
|
3
|
+
require "notiffany/notifier/tmux/client"
|
4
|
+
require "notiffany/notifier/tmux/session"
|
5
|
+
require "notiffany/notifier/tmux/notification"
|
3
6
|
|
4
7
|
# TODO: this probably deserves a gem of it's own
|
5
8
|
module Notiffany
|
@@ -27,134 +30,6 @@ module Notiffany
|
|
27
30
|
color_location: "status-left-bg"
|
28
31
|
}
|
29
32
|
|
30
|
-
class Client
|
31
|
-
CLIENT = "tmux"
|
32
|
-
|
33
|
-
class << self
|
34
|
-
def version
|
35
|
-
Float(_capture("-V")[/\d+\.\d+/])
|
36
|
-
end
|
37
|
-
|
38
|
-
def _capture(*args)
|
39
|
-
Shellany::Sheller.stdout(([CLIENT] + args).join(" "))
|
40
|
-
end
|
41
|
-
|
42
|
-
def _run(*args)
|
43
|
-
Shellany::Sheller.run(([CLIENT] + args).join(" "))
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def initialize(client)
|
48
|
-
@client = client
|
49
|
-
end
|
50
|
-
|
51
|
-
def clients
|
52
|
-
return [@client] unless @client == :all
|
53
|
-
ttys = _capture("list-clients", "-F", "'\#{client_tty}'")
|
54
|
-
ttys = ttys.split(/\n/)
|
55
|
-
|
56
|
-
# if user is running 'tmux -C' remove this client from list
|
57
|
-
ttys.delete("(null)")
|
58
|
-
ttys
|
59
|
-
end
|
60
|
-
|
61
|
-
def set(key, value)
|
62
|
-
clients.each do |client|
|
63
|
-
args = client ? ["-t", client.strip] : nil
|
64
|
-
_run("set", "-q", *args, key, value)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def display_message(message)
|
69
|
-
clients.each do |client|
|
70
|
-
args = ["-c", client.strip] if client
|
71
|
-
# TODO: should properly escape message here
|
72
|
-
_run("display", *args, "'#{message}'")
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def unset(key, value)
|
77
|
-
clients.each do |client|
|
78
|
-
args = client ? ["-t", client.strip] : []
|
79
|
-
if value
|
80
|
-
_run("set", "-q", *args, key, value)
|
81
|
-
else
|
82
|
-
_run("set", "-q", "-u", *args, key)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def parse_options
|
88
|
-
output = _capture("show", "-t", @client)
|
89
|
-
Hash[output.lines.map { |line| _parse_option(line) }]
|
90
|
-
end
|
91
|
-
|
92
|
-
def message_fg=(color)
|
93
|
-
set("message-fg", color)
|
94
|
-
end
|
95
|
-
|
96
|
-
def message_bg=(color)
|
97
|
-
set("message-bg", color)
|
98
|
-
end
|
99
|
-
|
100
|
-
def display_time=(time)
|
101
|
-
set("display-time", time)
|
102
|
-
end
|
103
|
-
|
104
|
-
def title=(string)
|
105
|
-
# TODO: properly escape?
|
106
|
-
set("set-titles-string", "'#{string}'")
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def _run(*args)
|
112
|
-
self.class._run(*args)
|
113
|
-
end
|
114
|
-
|
115
|
-
def _capture(*args)
|
116
|
-
self.class._capture(*args)
|
117
|
-
end
|
118
|
-
|
119
|
-
def _parse_option(line)
|
120
|
-
line.partition(" ").map(&:strip).reject(&:empty?)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
class Session
|
125
|
-
def initialize
|
126
|
-
@options_store = {}
|
127
|
-
|
128
|
-
# NOTE: we are reading the settings of all clients
|
129
|
-
# - regardless of the :display_on_all_clients option
|
130
|
-
|
131
|
-
# Ideally, this should be done incrementally (e.g. if we start with
|
132
|
-
# "current" client and then override the :display_on_all_clients to
|
133
|
-
# true, only then the option store should be updated to contain
|
134
|
-
# settings of all clients
|
135
|
-
Client.new(:all).clients.each do |client|
|
136
|
-
@options_store[client] = {
|
137
|
-
"status-left-bg" => nil,
|
138
|
-
"status-right-bg" => nil,
|
139
|
-
"status-left-fg" => nil,
|
140
|
-
"status-right-fg" => nil,
|
141
|
-
"message-bg" => nil,
|
142
|
-
"message-fg" => nil,
|
143
|
-
"display-time" => nil
|
144
|
-
}.merge(Client.new(client).parse_options)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def close
|
149
|
-
@options_store.each do |client, options|
|
150
|
-
options.each do |key, value|
|
151
|
-
Client.new(client).unset(key, value)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
@options_store = nil
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
33
|
class Error < RuntimeError
|
159
34
|
end
|
160
35
|
|
@@ -226,129 +101,31 @@ module Notiffany
|
|
226
101
|
# message on all tmux clients or not
|
227
102
|
#
|
228
103
|
def _perform_notify(message, options = {})
|
229
|
-
change_color = options[:change_color]
|
230
104
|
locations = Array(options[:color_location])
|
231
|
-
display_the_title = options[:display_title]
|
232
|
-
display_message = options[:display_message]
|
233
105
|
type = options[:type].to_s
|
234
106
|
title = options[:title]
|
235
107
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
_display_title(type, title, message, options) if display_the_title
|
244
|
-
|
245
|
-
return unless display_message
|
246
|
-
_display_message(type, title, message, options)
|
247
|
-
end
|
248
|
-
|
249
|
-
# Displays a message in the title bar of the terminal.
|
250
|
-
#
|
251
|
-
# @param [String] title the notification title
|
252
|
-
# @param [String] message the notification message body
|
253
|
-
# @param [Hash] options additional notification library options
|
254
|
-
# @option options [String] success_message_format a string to use as
|
255
|
-
# formatter for the success message.
|
256
|
-
# @option options [String] failed_message_format a string to use as
|
257
|
-
# formatter for the failed message.
|
258
|
-
# @option options [String] pending_message_format a string to use as
|
259
|
-
# formatter for the pending message.
|
260
|
-
# @option options [String] default_message_format a string to use as
|
261
|
-
# formatter when no format per type is defined.
|
262
|
-
#
|
263
|
-
def _display_title(type, title, message, options = {})
|
264
|
-
format = "#{type}_title_format".to_sym
|
265
|
-
default_title_format = options[:default_title_format]
|
266
|
-
title_format = options.fetch(format, default_title_format)
|
267
|
-
teaser_message = message.split("\n").first
|
268
|
-
display_title = title_format % [title, teaser_message]
|
269
|
-
|
270
|
-
Client.new(client(options)).title = display_title
|
271
|
-
end
|
272
|
-
|
273
|
-
# Displays a message in the status bar of tmux.
|
274
|
-
#
|
275
|
-
# @param [String] type the notification type. Either 'success',
|
276
|
-
# 'pending', 'failed' or 'notify'
|
277
|
-
# @param [String] title the notification title
|
278
|
-
# @param [String] message the notification message body
|
279
|
-
# @param [Hash] options additional notification library options
|
280
|
-
# @option options [Integer] timeout the amount of seconds to show the
|
281
|
-
# message in the status bar
|
282
|
-
# @option options [String] success_message_format a string to use as
|
283
|
-
# formatter for the success message.
|
284
|
-
# @option options [String] failed_message_format a string to use as
|
285
|
-
# formatter for the failed message.
|
286
|
-
# @option options [String] pending_message_format a string to use as
|
287
|
-
# formatter for the pending message.
|
288
|
-
# @option options [String] default_message_format a string to use as
|
289
|
-
# formatter when no format per type is defined.
|
290
|
-
# @option options [String] success_message_color the success notification
|
291
|
-
# foreground color name.
|
292
|
-
# @option options [String] failed_message_color the failed notification
|
293
|
-
# foreground color name.
|
294
|
-
# @option options [String] pending_message_color the pending notification
|
295
|
-
# foreground color name.
|
296
|
-
# @option options [String] default_message_color a notification
|
297
|
-
# foreground color to use when no color per type is defined.
|
298
|
-
# @option options [String] line_separator a string to use instead of a
|
299
|
-
# line-break.
|
300
|
-
#
|
301
|
-
def _display_message(type, title, message, opts = {})
|
302
|
-
default_format = opts[:default_message_format]
|
303
|
-
default_color = opts[:default_message_color]
|
304
|
-
display_time = opts[:timeout]
|
305
|
-
separator = opts[:line_separator]
|
306
|
-
|
307
|
-
format = "#{type}_message_format".to_sym
|
308
|
-
message_format = opts.fetch(format, default_format)
|
309
|
-
|
310
|
-
color = "#{type}_message_color".to_sym
|
311
|
-
message_color = opts.fetch(color, default_color)
|
312
|
-
|
313
|
-
color = _tmux_color(type, opts)
|
314
|
-
formatted_message = message.split("\n").join(separator)
|
315
|
-
msg = message_format % [title, formatted_message]
|
316
|
-
|
317
|
-
cl = Client.new(client(opts))
|
318
|
-
cl.display_time = display_time * 1000
|
319
|
-
cl.message_fg = message_color
|
320
|
-
cl.message_bg = color
|
321
|
-
cl.display_message(msg)
|
322
|
-
end
|
323
|
-
|
324
|
-
# Get the Tmux color for the notification type.
|
325
|
-
# You can configure your own color by overwriting the defaults.
|
326
|
-
#
|
327
|
-
# @param [String] type the notification type
|
328
|
-
# @return [String] the name of the emacs color
|
329
|
-
#
|
330
|
-
def _tmux_color(type, opts = {})
|
331
|
-
type = type.to_sym
|
332
|
-
opts[type] || opts[:default]
|
108
|
+
tmux = Notification.new(type, options)
|
109
|
+
tmux.colorize(locations) if options[:change_color]
|
110
|
+
tmux.display_title(title, message) if options[:display_title]
|
111
|
+
tmux.display_message(title, message) if options[:display_message]
|
333
112
|
end
|
334
113
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
def self._end_session
|
341
|
-
fail "Already turned off!" unless @session || nil
|
342
|
-
@session.close
|
343
|
-
@session = nil
|
344
|
-
end
|
114
|
+
class << self
|
115
|
+
def _start_session
|
116
|
+
fail "Already turned on!" if @session
|
117
|
+
@session = Session.new
|
118
|
+
end
|
345
119
|
|
346
|
-
|
347
|
-
|
348
|
-
|
120
|
+
def _end_session
|
121
|
+
fail "Already turned off!" unless @session
|
122
|
+
@session.close
|
123
|
+
@session = nil
|
124
|
+
end
|
349
125
|
|
350
|
-
|
351
|
-
|
126
|
+
def _session
|
127
|
+
@session
|
128
|
+
end
|
352
129
|
end
|
353
130
|
end
|
354
131
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require "shellany/sheller"
|
2
|
+
|
3
|
+
module Notiffany
|
4
|
+
class Notifier
|
5
|
+
class Tmux < Base
|
6
|
+
# Class for actually calling TMux to run commands
|
7
|
+
class Client
|
8
|
+
CLIENT = "tmux".freeze
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def version
|
12
|
+
Float(_capture("-V")[/\d+\.\d+/])
|
13
|
+
end
|
14
|
+
|
15
|
+
def _capture(*args)
|
16
|
+
Shellany::Sheller.stdout(([CLIENT] + args).join(" "))
|
17
|
+
end
|
18
|
+
|
19
|
+
def _run(*args)
|
20
|
+
Shellany::Sheller.run(([CLIENT] + args).join(" "))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(client)
|
25
|
+
@client = client
|
26
|
+
end
|
27
|
+
|
28
|
+
def clients
|
29
|
+
return [@client] unless @client == :all
|
30
|
+
ttys = _capture("list-clients", "-F", "'\#{client_tty}'")
|
31
|
+
ttys = ttys.split(/\n/)
|
32
|
+
|
33
|
+
# if user is running 'tmux -C' remove this client from list
|
34
|
+
ttys.delete("(null)")
|
35
|
+
ttys
|
36
|
+
end
|
37
|
+
|
38
|
+
def set(key, value)
|
39
|
+
clients.each do |client|
|
40
|
+
args = client ? ["-t", client.strip] : nil
|
41
|
+
_run("set", "-q", *args, key, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def display_message(message)
|
46
|
+
clients.each do |client|
|
47
|
+
args = ["-c", client.strip] if client
|
48
|
+
# TODO: should properly escape message here
|
49
|
+
_run("display", *args, "'#{message}'")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def unset(key, value)
|
54
|
+
clients.each do |client|
|
55
|
+
_run(*_all_args_for(key, value, client))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_options
|
60
|
+
output = _capture("show", "-t", @client)
|
61
|
+
Hash[output.lines.map { |line| _parse_option(line) }]
|
62
|
+
end
|
63
|
+
|
64
|
+
def message_fg=(color)
|
65
|
+
set("message-fg", color)
|
66
|
+
end
|
67
|
+
|
68
|
+
def message_bg=(color)
|
69
|
+
set("message-bg", color)
|
70
|
+
end
|
71
|
+
|
72
|
+
def display_time=(time)
|
73
|
+
set("display-time", time)
|
74
|
+
end
|
75
|
+
|
76
|
+
def title=(string)
|
77
|
+
# TODO: properly escape?
|
78
|
+
set("set-titles-string", "'#{string}'")
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def _run(*args)
|
84
|
+
self.class._run(*args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def _capture(*args)
|
88
|
+
self.class._capture(*args)
|
89
|
+
end
|
90
|
+
|
91
|
+
def _parse_option(line)
|
92
|
+
line.partition(" ").map(&:strip).reject(&:empty?)
|
93
|
+
end
|
94
|
+
|
95
|
+
def _all_args_for(key, value, client)
|
96
|
+
unset = value ? [] : %w(-u)
|
97
|
+
args = client ? ["-t", client.strip] : []
|
98
|
+
["set", "-q", *unset, *args, key, *[value].compact]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Notiffany
|
2
|
+
class Notifier
|
3
|
+
class Tmux < Base
|
4
|
+
# Wraps a notification with it's options
|
5
|
+
class Notification
|
6
|
+
def initialize(type, options)
|
7
|
+
@type = type
|
8
|
+
@options = options
|
9
|
+
@color = options[type.to_sym] || options[:default]
|
10
|
+
@separator = options[:line_separator]
|
11
|
+
@message_color = _value_for(:message_color)
|
12
|
+
@client = Client.new(options[:display_on_all_clients] ? :all : nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def display_title(title, message)
|
16
|
+
title_format = _value_for(:title_format)
|
17
|
+
|
18
|
+
teaser_message = message.split("\n").first
|
19
|
+
display_title = format(title_format, title, teaser_message)
|
20
|
+
|
21
|
+
client.title = display_title
|
22
|
+
end
|
23
|
+
|
24
|
+
def display_message(title, message)
|
25
|
+
message = _message_for(title, message)
|
26
|
+
|
27
|
+
client.display_time = options[:timeout] * 1000
|
28
|
+
client.message_fg = message_color
|
29
|
+
client.message_bg = color
|
30
|
+
client.display_message(message)
|
31
|
+
end
|
32
|
+
|
33
|
+
def colorize(locations)
|
34
|
+
locations.each do |location|
|
35
|
+
client.set(location, color)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :type
|
42
|
+
attr_reader :options
|
43
|
+
attr_reader :color
|
44
|
+
attr_reader :message_color
|
45
|
+
attr_reader :client
|
46
|
+
attr_reader :separator
|
47
|
+
|
48
|
+
def _value_for(field)
|
49
|
+
format = "#{type}_#{field}".to_sym
|
50
|
+
default = options["default_#{field}".to_sym]
|
51
|
+
options.fetch(format, default)
|
52
|
+
end
|
53
|
+
|
54
|
+
def _message_for(title, message)
|
55
|
+
message_format = _value_for(:message_format)
|
56
|
+
formatted_message = message.split("\n").join(separator)
|
57
|
+
format(message_format, title, formatted_message)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Notiffany
|
2
|
+
class Notifier
|
3
|
+
class Tmux < Base
|
4
|
+
# Preserves TMux settings for all tmux sessions
|
5
|
+
class Session
|
6
|
+
def initialize
|
7
|
+
@options_store = {}
|
8
|
+
|
9
|
+
# NOTE: we are reading the settings of all clients
|
10
|
+
# - regardless of the :display_on_all_clients option
|
11
|
+
|
12
|
+
# Ideally, this should be done incrementally (e.g. if we start with
|
13
|
+
# "current" client and then override the :display_on_all_clients to
|
14
|
+
# true, only then the option store should be updated to contain
|
15
|
+
# settings of all clients
|
16
|
+
Client.new(:all).clients.each do |client|
|
17
|
+
@options_store[client] = {
|
18
|
+
"status-left-bg" => nil,
|
19
|
+
"status-right-bg" => nil,
|
20
|
+
"status-left-fg" => nil,
|
21
|
+
"status-right-fg" => nil,
|
22
|
+
"message-bg" => nil,
|
23
|
+
"message-fg" => nil,
|
24
|
+
"display-time" => nil
|
25
|
+
}.merge(Client.new(client).parse_options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def close
|
30
|
+
@options_store.each do |client, options|
|
31
|
+
options.each do |key, value|
|
32
|
+
Client.new(client).unset(key, value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@options_store = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/notiffany/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: notiffany
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cezary Baginski
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2016-05-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nenv
|
@@ -71,8 +71,10 @@ files:
|
|
71
71
|
- lib/notiffany.rb
|
72
72
|
- lib/notiffany/notifier.rb
|
73
73
|
- lib/notiffany/notifier/base.rb
|
74
|
+
- lib/notiffany/notifier/config.rb
|
74
75
|
- lib/notiffany/notifier/detected.rb
|
75
76
|
- lib/notiffany/notifier/emacs.rb
|
77
|
+
- lib/notiffany/notifier/emacs/client.rb
|
76
78
|
- lib/notiffany/notifier/file.rb
|
77
79
|
- lib/notiffany/notifier/gntp.rb
|
78
80
|
- lib/notiffany/notifier/growl.rb
|
@@ -82,6 +84,9 @@ files:
|
|
82
84
|
- lib/notiffany/notifier/terminal_notifier.rb
|
83
85
|
- lib/notiffany/notifier/terminal_title.rb
|
84
86
|
- lib/notiffany/notifier/tmux.rb
|
87
|
+
- lib/notiffany/notifier/tmux/client.rb
|
88
|
+
- lib/notiffany/notifier/tmux/notification.rb
|
89
|
+
- lib/notiffany/notifier/tmux/session.rb
|
85
90
|
- lib/notiffany/version.rb
|
86
91
|
homepage: https://github.com/guard/notiffany
|
87
92
|
licenses:
|
@@ -103,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
108
|
version: '0'
|
104
109
|
requirements: []
|
105
110
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.5.1
|
107
112
|
signing_key:
|
108
113
|
specification_version: 4
|
109
114
|
summary: Notifier library (extracted from Guard project)
|