topinambour 1.0.11 → 1.0.12
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 +121 -30
- data/bin/topinambour +12 -11
- data/data/app-menu.ui +8 -4
- data/data/gschemas.compiled +0 -0
- data/data/headerbar.ui +6 -64
- data/data/main-menu-popover.ui +131 -0
- data/data/prefs-dialog.ui +405 -505
- data/data/shortcuts.ui +130 -0
- data/data/topinambour.gresource +0 -0
- data/data/topinambour.gresource.xml +2 -19
- data/data/topinambour.gschema.xml +72 -0
- data/lib/actions.rb +12 -13
- data/lib/application.rb +73 -60
- data/lib/color_selector.rb +16 -14
- data/lib/font_selector.rb +8 -14
- data/lib/notebook.rb +22 -11
- data/lib/preferences.rb +159 -114
- data/lib/shortcuts.rb +6 -18
- data/lib/terminal.rb +76 -33
- data/lib/terminal_chooser.rb +247 -110
- data/lib/window.rb +48 -47
- metadata +7 -34
- data/data/#app-menu.ui# +0 -11
- data/data/application-exit-symbolic.svg +0 -32
- data/data/color-select-symbolic.svg +0 -34
- data/data/emblem-photos-symbolic.svg +0 -33
- data/data/font-select-symbolic.svg +0 -33
- data/data/pan-end-symbolic.svg +0 -31
- data/data/pan-start-symbolic.svg +0 -31
- data/data/tab-new-symbolic.svg +0 -34
- data/data/window-close-symbolic.svg +0 -28
- data/lib/css_handler.rb +0 -241
- data/lib/style_properties.rb +0 -171
data/lib/css_handler.rb
DELETED
@@ -1,241 +0,0 @@
|
|
1
|
-
# Copyright 2016 Cedric LE MOIGNE, cedlemo@gmx.com
|
2
|
-
# This file is part of Topinambour.
|
3
|
-
#
|
4
|
-
# Topinambour is free software: you can redistribute it and/or modify
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
7
|
-
# any later version.
|
8
|
-
#
|
9
|
-
# Topinambour is distributed in the hope that it will be useful,
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
-
# GNU General Public License for more details.
|
13
|
-
#
|
14
|
-
# You should have received a copy of the GNU General Public License
|
15
|
-
# along with Topinambour. If not, see <http://www.gnu.org/licenses/>.
|
16
|
-
|
17
|
-
##
|
18
|
-
# This module contains all the methods needed to read, parse
|
19
|
-
# and modify css file.
|
20
|
-
# Sass is used to read, parse and get informations about
|
21
|
-
# css selectors or properties
|
22
|
-
# The modifying or addition of css properties are done
|
23
|
-
# with ruby strings facilities
|
24
|
-
module CssHandler
|
25
|
-
def self.css_file?(filename)
|
26
|
-
filename =~ /^.*\.css$/ ? true : false
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.scss_file?(filename)
|
30
|
-
filename =~ /^.*\.scss$/ ? true : false
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.sass_file?(filename)
|
34
|
-
filename =~ /^.*\.sass$/ ? true : false
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.to_css(filename)
|
38
|
-
content = File.open(filename, "r").read
|
39
|
-
if css_file?(filename) || scss_file?(filename)
|
40
|
-
Sass::Engine.new(content, :syntax => :scss).render
|
41
|
-
elsif sass_file?(filename)
|
42
|
-
Sass::Engine.new(content, :syntax => :sass).render
|
43
|
-
else
|
44
|
-
puts "Your theme file must be a css, scss or sass file"
|
45
|
-
exit 1
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.to_engine(filename)
|
50
|
-
content = File.open(filename, "r").read
|
51
|
-
if css_file?(filename) || scss_file?(filename)
|
52
|
-
Sass::Engine.new(content, :syntax => :scss)
|
53
|
-
elsif sass_file?(filename)
|
54
|
-
Sass::Engine.new(content, :syntax => :sass)
|
55
|
-
else
|
56
|
-
puts "Your theme file must be a css, scss or sass file"
|
57
|
-
exit 1
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.reload_engine(engine, css_content)
|
62
|
-
Sass::Engine.new(css_content, :syntax => engine.options[:syntax])
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.color_property?(value)
|
66
|
-
parsed_color = nil
|
67
|
-
begin
|
68
|
-
parsed_color = Gdk::RGBA.parse(value)
|
69
|
-
rescue
|
70
|
-
parsed_color = nil
|
71
|
-
end
|
72
|
-
parsed_color ? true : false
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.value_to_css_value(value)
|
76
|
-
if value.class == String && color_property?(value)
|
77
|
-
"#{value}"
|
78
|
-
elsif value.class == String
|
79
|
-
%("#{value}")
|
80
|
-
else
|
81
|
-
"#{value}"
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.property_to_css_instructions(name, value)
|
87
|
-
"#{name}: #{value_to_css_value(value)}"
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.props_with_name(tree, prop_name)
|
91
|
-
props = []
|
92
|
-
tree.children.each do |node|
|
93
|
-
node.each do |prop|
|
94
|
-
next if prop.class != Sass::Tree::PropNode
|
95
|
-
name = prop.name[0]
|
96
|
-
props << prop if name == prop_name
|
97
|
-
end
|
98
|
-
end
|
99
|
-
props
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.prop_position(prop)
|
103
|
-
source_range = prop.source_range
|
104
|
-
[source_range.start_pos, source_range.end_pos]
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.property_defined?(tree, name)
|
108
|
-
tree.children.each do |node|
|
109
|
-
node.each do |prop|
|
110
|
-
next if prop.class != Sass::Tree::PropNode
|
111
|
-
next if prop.class == Sass::Tree::CommentNode
|
112
|
-
return true if prop.name[0] == name
|
113
|
-
end
|
114
|
-
end
|
115
|
-
false
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.modify_in_ranges(line, line_number, start_range, end_range, value)
|
119
|
-
if line_number < start_range.line || line_number > end_range.line
|
120
|
-
line
|
121
|
-
else
|
122
|
-
tmp = ""
|
123
|
-
if line_number == start_range.line
|
124
|
-
tmp += line[0..(start_range.offset - 2)] + value_to_css_value(value)
|
125
|
-
end
|
126
|
-
tmp += line[(end_range.offset - 1)..-1] if line_number == end_range.line
|
127
|
-
tmp
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def self.modify_property_value(file_content, property, value)
|
132
|
-
start_range = property.value_source_range.start_pos
|
133
|
-
end_range = property.value_source_range.end_pos
|
134
|
-
tmp = ""
|
135
|
-
line_number = 1
|
136
|
-
file_content.each_line do |line|
|
137
|
-
tmp += modify_in_ranges(line, line_number, start_range, end_range, value)
|
138
|
-
line_number += 1
|
139
|
-
end
|
140
|
-
tmp
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.modify_each_property_values(css_content, engine, prop)
|
144
|
-
engine = engine
|
145
|
-
tree = engine.to_tree
|
146
|
-
props = props_with_name(tree, prop[:name])
|
147
|
-
new_css = css_content
|
148
|
-
(0..(props.size - 1)).each do |i|
|
149
|
-
new_css = modify_property_value(new_css, props[i], prop[:value])
|
150
|
-
engine = reload_engine(engine, new_css)
|
151
|
-
tree = engine.to_tree
|
152
|
-
props = props_with_name(tree, prop[:name])
|
153
|
-
end
|
154
|
-
new_css
|
155
|
-
end
|
156
|
-
|
157
|
-
def self.append_new_property_after_line(line, prop, indent)
|
158
|
-
tmp = line.gsub(/\;[^\;]*$/, ";\n")
|
159
|
-
new_prop = property_to_css_instructions(prop[:name], prop[:value])
|
160
|
-
tmp += (indent + new_prop + (Regexp.last_match(0) || ";\n"))
|
161
|
-
tmp
|
162
|
-
end
|
163
|
-
|
164
|
-
def self.last_child_which_is_not_comment(selector)
|
165
|
-
son = nil
|
166
|
-
selector.children.each do |child|
|
167
|
-
son = child unless child.class == Sass::Tree::CommentNode
|
168
|
-
end
|
169
|
-
son
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.compute_position_to_append(selector, element)
|
173
|
-
indent = last_line = nil
|
174
|
-
if element
|
175
|
-
indent = " " * (element.name_source_range.start_pos.offset - 1) || ""
|
176
|
-
last_line = element.value_source_range.end_pos.line
|
177
|
-
else # If we don 't have any property in selector, use sel offset
|
178
|
-
indent = " " * (selector.source_range.start_pos.offset - 1) || ""
|
179
|
-
last_line = selector.source_range.start_pos.line
|
180
|
-
end
|
181
|
-
[indent, last_line]
|
182
|
-
end
|
183
|
-
|
184
|
-
def self.append_property_in_universal_selector(css_content, engine, prop)
|
185
|
-
last_selector = selectors_with_name(engine.to_tree, "*").last
|
186
|
-
last_prop = last_child_which_is_not_comment(last_selector)
|
187
|
-
indent, last_line = compute_position_to_append(last_selector, last_prop)
|
188
|
-
tmp = ""
|
189
|
-
line_number = 1
|
190
|
-
css_content.each_line do |line|
|
191
|
-
if last_line == line_number
|
192
|
-
tmp += append_new_property_after_line(line, prop, indent)
|
193
|
-
else
|
194
|
-
tmp += line
|
195
|
-
end
|
196
|
-
line_number += 1
|
197
|
-
end
|
198
|
-
tmp
|
199
|
-
end
|
200
|
-
|
201
|
-
def self.rule_node_name_is?(node, name)
|
202
|
-
if node.rule.include?(name)
|
203
|
-
true
|
204
|
-
elsif node.parsed_rules.to_s == name
|
205
|
-
true
|
206
|
-
elsif node.resolved_rules == name
|
207
|
-
true
|
208
|
-
else
|
209
|
-
false
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def self.selectors_with_name(tree, sel_name)
|
214
|
-
selectors = []
|
215
|
-
tree.children.each do |node|
|
216
|
-
next unless node.class == Sass::Tree::RuleNode
|
217
|
-
selectors << node if rule_node_name_is?(node, sel_name)
|
218
|
-
end
|
219
|
-
selectors
|
220
|
-
end
|
221
|
-
|
222
|
-
def self.update_css_with_new_property(content, engine, prop)
|
223
|
-
if property_defined?(engine.to_tree, prop[:name])
|
224
|
-
modify_each_property_values(content, engine, prop)
|
225
|
-
else
|
226
|
-
append_property_in_universal_selector(content, engine, prop)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
def self.update_css(filename, properties)
|
231
|
-
engine = to_engine(filename)
|
232
|
-
new_css = nil
|
233
|
-
content = File.open(filename, "r").read
|
234
|
-
properties.each do |prop|
|
235
|
-
new_css = update_css_with_new_property(content, engine, prop)
|
236
|
-
engine = reload_engine(engine, new_css)
|
237
|
-
content = new_css
|
238
|
-
end
|
239
|
-
new_css
|
240
|
-
end
|
241
|
-
end
|
data/lib/style_properties.rb
DELETED
@@ -1,171 +0,0 @@
|
|
1
|
-
# Copyright 2016 Cedric LE MOIGNE, cedlemo@gmx.com
|
2
|
-
# This file is part of Topinambour.
|
3
|
-
#
|
4
|
-
# Topinambour is free software: you can redistribute it and/or modify
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
7
|
-
# any later version.
|
8
|
-
#
|
9
|
-
# Topinambour is distributed in the hope that it will be useful,
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
-
# GNU General Public License for more details.
|
13
|
-
#
|
14
|
-
# You should have received a copy of the GNU General Public License
|
15
|
-
# along with Topinambour. If not, see <http://www.gnu.org/licenses/>.
|
16
|
-
|
17
|
-
module TopinambourStyleProperties
|
18
|
-
def generate_string_rw_property(name, args)
|
19
|
-
GLib::Param::String.new(name.downcase,
|
20
|
-
name.capitalize,
|
21
|
-
name.upcase,
|
22
|
-
args,
|
23
|
-
GLib::Param::READABLE |
|
24
|
-
GLib::Param::WRITABLE)
|
25
|
-
end
|
26
|
-
|
27
|
-
def generate_boolean_rw_property(name, args)
|
28
|
-
GLib::Param::Boolean.new(name.downcase,
|
29
|
-
name.capitalize,
|
30
|
-
name.upcase,
|
31
|
-
args,
|
32
|
-
GLib::Param::READABLE |
|
33
|
-
GLib::Param::WRITABLE)
|
34
|
-
end
|
35
|
-
|
36
|
-
def generate_int_rw_property(name, args)
|
37
|
-
GLib::Param::Int.new(name.downcase,
|
38
|
-
name.capitalize,
|
39
|
-
name.upcase,
|
40
|
-
*args,
|
41
|
-
GLib::Param::READABLE |
|
42
|
-
GLib::Param::WRITABLE)
|
43
|
-
end
|
44
|
-
|
45
|
-
def generate_enum_rw_property(name, args)
|
46
|
-
GLib::Param::Enum.new(name.downcase,
|
47
|
-
name.capitalize,
|
48
|
-
name.upcase,
|
49
|
-
*args,
|
50
|
-
GLib::Param::READABLE |
|
51
|
-
GLib::Param::WRITABLE)
|
52
|
-
end
|
53
|
-
|
54
|
-
def generate_boxed_rw_property(name, args)
|
55
|
-
GLib::Param::Boxed.new(name.downcase,
|
56
|
-
name.capitalize,
|
57
|
-
name.upcase,
|
58
|
-
args,
|
59
|
-
GLib::Param::READABLE |
|
60
|
-
GLib::Param::WRITABLE)
|
61
|
-
end
|
62
|
-
|
63
|
-
def generate_rw_property(type, name, args)
|
64
|
-
type = type.to_s.downcase
|
65
|
-
method_name = "generate_#{type}_rw_property"
|
66
|
-
return false unless methods.include?(method_name.to_sym)
|
67
|
-
method(method_name.to_sym).call(name, args)
|
68
|
-
end
|
69
|
-
|
70
|
-
def install_style(type, name, args)
|
71
|
-
property = generate_rw_property(type, name, args)
|
72
|
-
install_style_property(property) if property
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
TERMINAL_COLOR_NAMES = [:foreground, :background, :black, :red, :green, :yellow,
|
77
|
-
:blue, :magenta, :cyan, :white, :brightblack,
|
78
|
-
:brightred, :brightgreen, :brightyellow, :brightblue,
|
79
|
-
:brightmagenta, :brightcyan, :brightwhite
|
80
|
-
]
|
81
|
-
DEFAULT_TERMINAL_COLORS = %w(#aeafad #323232 #000000 #b9214f #A6E22E #ff9800
|
82
|
-
#3399ff #8e33ff #06a2dc #B0B0B0 #5D5D5D #ff5c8d
|
83
|
-
#CDEE69 #ffff00 #9CD9F0 #FBB1F9 #77DFD8 #F7F7F7)
|
84
|
-
DEFAULT_TERMINAL_FONT = "Monospace 11"
|
85
|
-
|
86
|
-
class TopinambourTerminal < Vte::Terminal
|
87
|
-
extend TopinambourStyleProperties
|
88
|
-
type_register
|
89
|
-
TERMINAL_COLOR_NAMES.each_with_index do |c|
|
90
|
-
name = c.to_s
|
91
|
-
install_style("boxed",
|
92
|
-
name,
|
93
|
-
GLib::Type["GdkRGBA"])
|
94
|
-
end
|
95
|
-
install_style("boxed", "font",
|
96
|
-
GLib::Type["PangoFontDescription"])
|
97
|
-
install_style("boolean", "audible-bell", false)
|
98
|
-
install_style("boolean", "allow-bold", true)
|
99
|
-
install_style("boolean", "scroll-on-output", true)
|
100
|
-
install_style("boolean", "scroll-on-keystroke", true)
|
101
|
-
install_style("boolean", "rewrap-on-resize", true)
|
102
|
-
install_style("boolean", "mouse-autohide", true)
|
103
|
-
install_style("enum", "cursor-shape", [GLib::Type["VteCursorShape"],
|
104
|
-
Vte::CursorShape::BLOCK])
|
105
|
-
install_style("enum", "cursor-blink-mode", [GLib::Type["VteCursorBlinkMode"],
|
106
|
-
Vte::CursorBlinkMode::SYSTEM])
|
107
|
-
install_style("enum", "backspace-binding", [GLib::Type["VteEraseBinding"],
|
108
|
-
Vte::EraseBinding::AUTO])
|
109
|
-
install_style("enum", "delete-binding", [GLib::Type["VteEraseBinding"],
|
110
|
-
Vte::EraseBinding::AUTO])
|
111
|
-
def load_properties
|
112
|
-
%w(audible_bell allow_bold scroll_on_output scroll_on_keystroke
|
113
|
-
rewrap_on_resize mouse_autohide).each do |prop|
|
114
|
-
send("#{prop}=", style_get_property(prop.gsub(/_/,"-")))
|
115
|
-
end
|
116
|
-
%w(cursor_shape cursor_blink_mode backspace_binding delete_binding).each do |prop|
|
117
|
-
send("#{prop}=", style_get_property(prop.gsub(/_/,"-")))
|
118
|
-
end
|
119
|
-
@colors = css_colors
|
120
|
-
apply_colors
|
121
|
-
set_font(css_font)
|
122
|
-
end
|
123
|
-
|
124
|
-
def parse_css_color(color_name)
|
125
|
-
color_index = TERMINAL_COLOR_NAMES.index(color_name.to_sym)
|
126
|
-
color_value = DEFAULT_TERMINAL_COLORS[color_index]
|
127
|
-
default_color = Gdk::RGBA.parse(color_value)
|
128
|
-
color_from_css = style_get_property(color_name)
|
129
|
-
color = color_from_css ? color_from_css : default_color
|
130
|
-
color
|
131
|
-
end
|
132
|
-
|
133
|
-
def css_colors
|
134
|
-
colors = []
|
135
|
-
background = parse_css_color(TERMINAL_COLOR_NAMES[0].to_s)
|
136
|
-
foreground = parse_css_color(TERMINAL_COLOR_NAMES[1].to_s)
|
137
|
-
TERMINAL_COLOR_NAMES[2..-1].each do |c|
|
138
|
-
colors << parse_css_color(c.to_s)
|
139
|
-
end
|
140
|
-
[background, foreground] + colors
|
141
|
-
end
|
142
|
-
|
143
|
-
def css_font
|
144
|
-
font = style_get_property("font")
|
145
|
-
font = Pango::FontDescription.new(DEFAULT_TERMINAL_FONT) unless font
|
146
|
-
font
|
147
|
-
end
|
148
|
-
|
149
|
-
def apply_colors
|
150
|
-
set_colors(@colors[0], @colors[1], @colors[2..-1])
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class TopinambourWindow < Gtk::ApplicationWindow
|
155
|
-
extend TopinambourStyleProperties
|
156
|
-
type_register
|
157
|
-
install_style("string", "shell", "/usr/bin/fish")
|
158
|
-
install_style("int", "width", [-1, 2000, 1000])
|
159
|
-
install_style("int", "height", [-1, 2000, 500])
|
160
|
-
|
161
|
-
def load_properties
|
162
|
-
_w, _h = self.size
|
163
|
-
w = style_get_property("width")
|
164
|
-
h = style_get_property("height")
|
165
|
-
w = _w if w == -1
|
166
|
-
h = _h if h == -1
|
167
|
-
self.resize(w, h)
|
168
|
-
self.set_default_size(w, h)
|
169
|
-
@shell = style_get_property("shell")
|
170
|
-
end
|
171
|
-
end
|