Go Back

0 /*

1 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>

2 *

3 * Permission to use, copy, modify, and distribute this software for any

4 * purpose with or without fee is hereby granted, provided that the above

5 * copyright notice and this permission notice appear in all copies.

6 *

7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES

8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF

13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

14 */

15 #ifdef __linux__

16 #define _GNU_SOURCE

17 #else

18 #define _BSD_SOURCE

19 #endif

20 #include <dirent.h>

21 #include <stddef.h>

22 #include <stdlib.h>

23 #include <errno.h>

24 #include <string.h>

25 #include <stdio.h>

26 #include <stdint.h>

27 #include <unistd.h>

28 #include "termbox.h"

29 #include "client.h"

30 #include "view.h"

31 #include "file.h"

32 #include "util.h"

33 #include "strlcpy.h"

34 #include "utf8.h"

35 #include "trash.h"

36

37 struct view *view_init(const char *path) {

38 struct view *view = malloc(sizeof(struct view));

39 file_init(view, path);

40 return view;

41 }

42

43 int format_path(const char *str, char *out, size_t length) {

44

45 size_t i = 0, j = 0;

46

47 while (str[i] && j < length - 1) {

48 size_t len = tb_utf8_char_length(str[i]);

49 if (len > 1) {

50 if (j + len > length) return -1;

51 memcpy(&out[j], &str[i], len);

52 i += len; j += len;

53 continue;

54 }

55 if (str[i] == '"') out[j++] = '\\';

56 out[j++] = str[i++];

57 }

58

59 out[j] = '\0';

60 return -(j >= length - 1); /* error if str was not properly copied */

61 }

62

63 void view_open(struct view *view) {

64

65 const char xdg[] = "xdg-open \"%s\" >/dev/null 2>&1 &";

66 char name[PATH_MAX];

67 char buf[sizeof(name) + sizeof(xdg) + 1];

68

69 if (view->length < 1 || view->fd == TRASH_FD)

70 return;

71

72 client.error = 0;

73 switch (view->entries[view->selected].type) {

74 case DT_REG:

75 chdir(view->path);

76 if (format_path(SELECTED(view).name, V(name))) {

77 STRCPY(client.info, "path too long");

78 client.error = 1;

79 break;

80 }

81 snprintf(V(buf), xdg, name);

82 system(buf);

83 break;

84 case DT_DIR:

85 if (file_cd(view, SELECTED(view).name)) {

86 STRCPY(client.info, strerror(errno));

87 client.error = 1;

88 break;

89 }

90 file_ls(view);

91 break;

92 }

93 }

94

95 void view_draw(struct view *view) {

96

97 size_t i = 0, start = TABS;

98

99 if (view->selected + 1 > view->scroll + HEIGHT)

100 view->scroll = view->selected - HEIGHT;

101 if (view->selected < view->scroll)

102 view->scroll = view->selected;

103

104 while (i + view->scroll < view->length) {

105 int selected;

106 struct entry *e;

107 uintattr_t fg, bg;

108

109 if (i > HEIGHT)

110 break;

111

112 fg = bg = TB_DEFAULT;

113

114 selected = view->selected == i + view->scroll;

115 e = &view->entries[i + view->scroll];

116 if (selected) {

117 fg = TB_WHITE;

118 bg = TB_CYAN;

119 }

120 if (e->type == DT_DIR)

121 fg = selected ? TB_BLACK : TB_CYAN;

122 if (e->selected)

123 bg = TB_CYAN;

124 if (e->selected && fg == TB_CYAN)

125 fg = TB_WHITE;

126 if (e->selected && selected)

127 fg = e->type == DT_REG ? TB_BLACK : TB_GREEN;

128 tb_print(0, i + start, fg, bg, e->name);

129 if (e->type == DT_DIR) {

130 tb_set_cell(utf8_width(e->name, PATH_MAX), i + start,

131 '/', fg, bg);

132 }

133 i++;

134 }

135 }

136

137 void view_select(struct view *view, const char *name) {

138 file_select(view, name);

139 if (view->length < HEIGHT) return;

140 if (view->selected >= view->length - HEIGHT / 2) {

141 view->scroll = view->length - HEIGHT - 1;

142 } else if (view->selected > HEIGHT / 2) {

143 view->scroll = view->selected - HEIGHT / 2;

144 }

145 }

146

147 void view_unselect(struct view *view) {

148 size_t i = 0;

149 while (i < view->length) {

150 view->entries[i].selected = 0;

151 i++;

152 }

153 }

154