1 /* Copyright (C) 2008 Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 WINDOW
*tree_window
, *info_window
;
20 GList
*lines
, *selected_line
, *first_line
, *last_line
;
24 lines
= g_list_append(lines
, tree_root
);
25 FILE(tree_root
)->line
= lines
;
26 selected_line
= lines
;
31 void init_curses(void)
43 getmaxyx(stdscr
, screen_size
[0], screen_size
[1]);
44 tree_window
= newwin(screen_size
[0] - 1, screen_size
[1], 0, 0);
45 info_window
= newwin(1, screen_size
[1], screen_size
[0] - 1, 0);
46 scrollok(tree_window
, TRUE
);
47 idlok(tree_window
, TRUE
);
50 void init_ui(char *name
)
55 print_line(FILE(tree_root
)->line
);
56 open_directory(tree_root
);
60 void refresh_screen(void)
62 wnoutrefresh(tree_window
);
63 wnoutrefresh(info_window
);
67 void handle_sigwinch(int signal_number
)
72 void print_lines(GList
*start_line
, GList
*end_line
, gboolean clear_bottom_lines
)
79 else if (start_line
!= NULL
) {
80 for (line_ptr
= start_line
;
81 g_list_position(first_line
, line_ptr
) < getmaxy(tree_window
);
82 line_ptr
= g_list_next(line_ptr
)) {
84 if (line_ptr
== end_line
)
88 line_number
= g_list_position(first_line
, last_line
) + 1;
89 if (clear_bottom_lines
&& line_number
< getmaxy(tree_window
)) {
90 wmove(tree_window
, line_number
, 0);
91 wclrtobot(tree_window
);
95 void print_parents_lines(GList
*line
)
100 for (file_ptr
= NODE(line
)->parent
, depth
= g_node_depth(file_ptr
) - 1;
101 !G_NODE_IS_ROOT(file_ptr
); file_ptr
= file_ptr
->parent
, depth
--) {
102 if (file_ptr
!= g_node_last_sibling(file_ptr
))
103 mvwaddch(tree_window
, g_list_position(first_line
, line
),
104 2 * depth
- 2, ACS_VLINE
);
106 mvwaddch(tree_window
, g_list_position(first_line
, line
),
108 mvwaddch(tree_window
, g_list_position(first_line
, line
), 2 * depth
- 1, ' ');
112 void print_line(GList
*line
)
114 int line_number
= g_list_position(first_line
, line
);
115 GNode
*file
= NODE(line
);
116 int depth
= g_node_depth(file
) - 1;
119 wmove(tree_window
, line_number
, 0);
120 wclrtoeol(tree_window
);
122 if (line
== selected_line
)
123 wattron(tree_window
, A_REVERSE
);
125 if (G_NODE_IS_ROOT(file
)) {
126 wattron(tree_window
, A_BOLD
);
127 waddnstr(tree_window
, FILE(file
)->name
, getmaxx(tree_window
) - 1);
128 if (!g_str_has_suffix(FILE(file
)->name
, "/"))
129 waddch(tree_window
, '/');
130 wattroff(tree_window
, A_BOLD
);
132 if (file
!= g_node_last_sibling(file
))
133 mvwaddch(tree_window
, line_number
, 2 * depth
- 2, ACS_LTEE
);
135 mvwaddch(tree_window
, line_number
, 2 * depth
- 2, ACS_LLCORNER
);
137 waddch(tree_window
, ACS_HLINE
);
138 if (FILE(file
)->link
== TRUE
) {
139 link_str
= g_strdup_printf("%s -> %s", FILE(file
)->name
,
140 FILE(file
)->link_path
);
141 waddnstr(tree_window
, link_str
, getmaxx(tree_window
) - 2 * depth
- 1);
144 waddnstr(tree_window
, FILE(file
)->name
,
145 getmaxx(tree_window
) - 2 * depth
- 1);
147 if (FILE(file
)->type
== directory_type
&& ((FILE(file
)->link
== TRUE
&&
148 !g_str_has_suffix(FILE(file
)->link_path
, "/")) ||
149 (FILE(file
)->link
== FALSE
&&
150 !g_str_has_suffix(FILE(file
)->name
, "/"))))
151 waddch(tree_window
, '/');
152 print_parents_lines(line
);
154 wattroff(tree_window
, A_REVERSE
);
157 void clear_info(void)
162 void print_info(char *message
, gboolean bold
)
164 static char *last_message
= NULL
;
165 static gboolean last_bold
= FALSE
;
167 if (message
!= NULL
) {
168 if (last_message
!= NULL
)
170 last_message
= strdup(message
);
172 if (bold
== TRUE
|| bold
== FALSE
)
174 if (last_bold
== TRUE
)
175 wattron(info_window
, A_BOLD
);
177 if (last_message
!= NULL
)
178 waddnstr(info_window
, last_message
, getmaxx(info_window
));
179 wattroff(info_window
, A_BOLD
);
182 void print_error_info(int last_errno
, char *file
, int line
, char *message
)
184 char *message_format
= "Error (%s:%i): %s";
188 message_str
= g_strdup_printf(message_format
, file
, line
, message
);
190 message_str
= g_strdup_printf(message_format
, file
, line
, strerror(last_errno
));
191 print_info(message_str
, TRUE
);
195 void update_last_line(void)
197 if (g_list_length(first_line
) > getmaxy(tree_window
))
198 last_line
= g_list_nth(first_line
, getmaxy(tree_window
) - 1);
200 last_line
= g_list_last(lines
);
203 void add_directory_content(GNode
*directory
)
205 GNode
*file_ptr
, *directory_sibling
;
208 directory_sibling
= get_next_file_not_deepper(directory
);
210 for (position
= g_list_position(lines
, FILE(directory
)->line
) + 1,
211 file_ptr
= g_node_first_child(directory
);
212 file_ptr
!= NULL
&& file_ptr
!= directory_sibling
;
213 position
++, file_ptr
= get_next_file(file_ptr
)) {
214 lines
= g_list_insert(lines
, file_ptr
, position
);
215 FILE(file_ptr
)->line
= g_list_nth(lines
, position
);
219 void open_directory(GNode
*directory
)
221 if (FILE(directory
)->read
== FALSE
&& read_directory(directory
) == FALSE
)
224 FILE(directory
)->open
= TRUE
;
225 add_directory_content(directory
);
227 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
230 void close_directory(GNode
*directory
)
232 GNode
*directory_sibling
;
235 directory_sibling
= get_next_file_not_deepper(directory
);
237 for (line_ptr
= g_list_next(FILE(directory
)->line
); line_ptr
!= NULL
&&
238 NODE(line_ptr
) != directory_sibling
; line_ptr
= g_list_next(FILE(directory
)->line
))
239 lines
= g_list_delete_link(lines
, line_ptr
);
241 FILE(directory
)->open
= FALSE
;
243 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
246 void update_directory(GNode
*directory
)
248 close_directory(directory
);
249 destroy_directory_content(directory
);
250 open_directory(directory
);
252 if (FILE(directory
)->show_dotfiles
== TRUE
)
253 show_dotfiles(directory
);
256 void show_dotfiles(GNode
*directory
)
258 add_dotfiles(directory
);
260 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
263 void hide_dotfiles(GNode
*directory
)
265 remove_dotfiles(directory
);
267 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
270 void select_line(GList
*line
)
272 select_nth_line(g_list_position(lines
, line
) - g_list_position(lines
, selected_line
));
275 void select_file(GNode
*file
)
277 select_line(FILE(file
)->line
);
280 void select_nth_line(int n_lines
)
282 GList
*old_selected_line
;
283 int min_n_lines
, max_n_lines
;
285 if ((max_n_lines
= g_list_length(selected_line
) - 1) < n_lines
)
286 n_lines
= max_n_lines
;
287 else if((min_n_lines
= (int) g_list_length(selected_line
) -
288 (int) g_list_length(lines
)) > n_lines
)
289 n_lines
= min_n_lines
;
291 old_selected_line
= selected_line
;
293 selected_line
= g_list_nth(lines
, g_list_position(lines
, selected_line
) + n_lines
);
294 else if (n_lines
> 0)
295 selected_line
= g_list_nth(selected_line
, n_lines
);
297 if (g_list_position(lines
, selected_line
) < g_list_position(lines
, first_line
))
298 scroll_tree(g_list_position(lines
, selected_line
) -
299 g_list_position(lines
, first_line
));
300 else if (g_list_position(lines
, selected_line
) > g_list_position(lines
, last_line
))
301 scroll_tree(g_list_position(lines
, selected_line
) -
302 g_list_position(lines
, last_line
));
305 print_line(selected_line
);
306 if (g_list_position(lines
, first_line
) <= g_list_position(lines
, old_selected_line
) &&
307 g_list_position(lines
, old_selected_line
) <=
308 g_list_position(lines
, last_line
))
309 print_line(old_selected_line
);
313 void scroll_tree(int n_lines
)
315 int min_n_lines
, max_n_lines
;
317 if ((min_n_lines
= -g_list_position(lines
, first_line
)) > n_lines
)
318 n_lines
= min_n_lines
;
319 else if ((max_n_lines
= g_list_length(last_line
) - 1) < n_lines
)
320 n_lines
= max_n_lines
;
322 wscrl(tree_window
, n_lines
);
324 first_line
= g_list_nth(lines
, g_list_position(lines
, first_line
) + n_lines
);
326 print_lines(first_line
, g_list_nth(first_line
, -n_lines
), FALSE
);
327 } else if (n_lines
> 0) {
328 first_line
= g_list_nth(first_line
, n_lines
);
330 print_lines(g_list_nth(lines
, g_list_position(lines
, last_line
) - n_lines
),
335 void select_line_inside_window(void)
337 if (g_list_position(lines
, selected_line
) < g_list_position(lines
, first_line
))
338 select_line(first_line
);
339 else if (g_list_position(lines
, selected_line
) > g_list_position(lines
, last_line
))
340 select_line(last_line
);
343 void select_next_line_by_first_letter(char letter
)
347 for (line_ptr
= g_list_next(selected_line
); line_ptr
!= NULL
;
348 line_ptr
= g_list_next(line_ptr
)) {
349 if (FILE(NODE(line_ptr
))->name
[0] == letter
) {
350 select_line(line_ptr
);
356 void select_previous_line_by_first_letter(char letter
)
360 for (line_ptr
= g_list_previous(selected_line
); line_ptr
!= NULL
;
361 line_ptr
= g_list_previous(line_ptr
)) {
362 if (FILE(NODE(line_ptr
))->name
[0] == letter
) {
363 select_line(line_ptr
);