💾 Archived View for gemini.rmf-dev.com › repo › Vaati › mz › files › d502c130b20d9c87b96610ad63f127e… captured on 2023-01-29 at 17:35:50. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

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 #include <stdlib.h>

16 #include "termbox.h"

17 #include "view.h"

18 #include "client.h"

19 #include "file.h"

20 #include "strlcpy.h"

21 #include "util.h"

22

23 struct client client;

24

25 static char *fetch_name(struct view *view) {

26 char *ptr = strrchr(view->path, '/');

27 if (!ptr) return NULL;

28 return ptr + 1;

29 }

30

31 static int name_length(struct view *view) {

32 char *ptr = strrchr(view->path, '/');

33 if (!ptr) return -1;

34 ptr++;

35 return strnlen(ptr, sizeof(view->path) - (ptr - view->path));

36 }

37

38 int client_init() {

39 client.view = view_init();

40 if (!client.view || file_ls(client.view)) return -1;

41 if (tb_init()) return -1;

42 client.width = tb_width();

43 client.height = tb_height();

44 return 0;

45 }

46

47 int client_clean() {

48 free(client.view);

49 return tb_shutdown();

50 }

51

52 static void client_tabbar(struct view *view) {

53 size_t sum_next, sum_prev;

54 struct view *ptr = view;

55

56 sum_next = 0;

57 while (ptr) {

58 sum_next += name_length(ptr) + 2;

59 ptr = ptr->next;

60 }

61

62 ptr = view->prev;

63 sum_prev = 0;

64 while (ptr) {

65 sum_prev += name_length(ptr) + 2;

66 if (!ptr->prev) break;

67 ptr = ptr->prev;

68 }

69 if (!ptr) ptr = view;

70

71 /* most likely scenario */

72 if (sum_prev + sum_next < (unsigned)client.width) {

73 size_t x = 0;

74 while (ptr) {

75 tb_printf(x, 0,

76 (ptr == view ? TB_DEFAULT : TB_UNDERLINE),

77 (ptr == view ? TB_DEFAULT : TB_WHITE),

78 " %s ", fetch_name(ptr));

79 x += name_length(ptr) + 2;

80 ptr = ptr->next;

81 }

82 while (x < (unsigned)client.width) {

83 tb_set_cell(x, 0, ' ', TB_DEFAULT, TB_WHITE);

84 x++;

85 }

86 } else if (sum_prev > client.width/2 && sum_next > client.width/2) {

87 /* draw to the left till it reach half width

88 * then start drawing to the right till it full width */

89 }

90

91 }

92

93 int client_update() {

94

95 char counter[32];

96 struct view *view = client.view;

97 size_t i;

98

99 tb_clear();

100

101 /* display list view */

102 view_draw(view);

103

104 /* display input field, error and counter */

105 tb_print(0, client.height - 1, TB_DEFAULT,

106 client.error ? TB_RED : TB_DEFAULT,

107 client.error ? client.info : client.field);

108

109 snprintf(V(counter), "%d", client.counter);

110 if (client.counter)

111 tb_print(client.width - 8, client.height - 1,

112 TB_DEFAULT, TB_DEFAULT, counter);

113

114 /* display white status bar */

115 i = 0;

116 while (i < client.width) {

117 tb_set_cell(i, client.height - 2, ' ', TB_BLACK, TB_WHITE);

118 i++;

119 }

120 tb_print(0, client.height - 2, TB_BLACK, TB_WHITE, view->path);

121

122

123 /* display tabs bar if there's more than one tab */

124 if (TABS) {

125 /*

126 * count the sum of file name length on prev tabs and the sum

127 * of those on next tabs,

128 * - if the sum of both sums is less than the client width than

129 * print all from x:0

130 * - else if the sum of the next tabs is less than half width

131 * but the sum of the prev tabs is more than half width than

132 * start by print from the last tab on the right

133 *

134 * (the current tab is counted as a next tab)

135 */

136 client_tabbar(view);

137 }

138

139 tb_present();

140

141 if (client_input()) return 1;

142 return 0;

143 }

144

145 static int newtab() {

146 struct view *new = view_init();

147

148 if (!new || file_ls(new)) {

149 snprintf(V(client.info), "%s", strerror(errno));

150 return -1;

151 }

152 if (client.view->next) {

153 new->next = client.view->next;

154 client.view->next->prev = new;

155 }

156 new->prev = client.view;

157 client.view->next = new;

158 new->selected = client.view->selected;

159 client.view = client.view->next;

160 return 0;

161 }

162

163 static int closetab() {

164

165 struct view *view = client.view;

166

167 if (!view) return -1;

168 client.view = NULL;

169 if (view->prev) {

170 view->prev->next = view->next;

171 client.view = view->prev;

172 }

173 if (view->next) {

174 view->next->prev = view->prev;

175 client.view = view->next;

176 }

177 if (client.view && file_ls(client.view)) {

178 snprintf(V(client.info), "%s", strerror(errno));

179 return -1;

180 }

181

182 free(view);

183 return client.view == NULL;

184 }

185

186 int parse_command() {

187

188 char *cmd = &client.field[1];

189

190 if (cmd[0] == 'q' && cmd[1] == '\0')

191 return closetab();

192 if (cmd[0] == 'q' && cmd[1] == 'a' && cmd[2] == '\0') {

193 while (!closetab()) ;

194 return 1;

195 }

196 if ((cmd[0] == 'n' && cmd[1] == 't' && cmd[2] == '\0') ||

197 !strncmp(cmd, "tabnew", sizeof(client.field) - 1))

198 return newtab();

199

200 snprintf(V(client.info), "Not a command: %s", cmd);

201 client.error = 1;

202 return 0;

203 }

204

205 int client_command(struct tb_event ev) {

206

207 int pos;

208

209 switch (ev.key) {

210 case TB_KEY_ESC:

211 client.command = 0;

212 client.field[0] = '\0';

213 return 0;

214 case TB_KEY_BACKSPACE2:

215 case TB_KEY_BACKSPACE:

216 pos = strnlen(client.field, sizeof(client.field));

217 if (pos > 1)

218 client.field[pos - 1] = '\0';

219 else

220 client.command = 0;

221 return 0;

222 case TB_KEY_ENTER:

223 pos = parse_command();

224 client.command = 0;

225 client.field[0] = '\0';

226 return pos;

227 }

228

229 if (!ev.ch) return 0;

230

231 pos = strnlen(client.field, sizeof(client.field));

232 client.field[pos] = ev.ch;

233 client.field[pos + 1] = '\0';

234

235 return 0;

236 }

237

238 void client_reset() {

239 client.counter = client.g = 0;

240 }

241

242 int client_input() {

243 struct tb_event ev;

244 struct view *view = client.view;

245

246 if (tb_poll_event(&ev) != TB_OK) {

247 return -1;

248 }

249

250 if (ev.type == TB_EVENT_RESIZE) {

251 client.width = ev.w;

252 client.height = ev.h;

253 return 0;

254 }

255

256 if (ev.type != TB_EVENT_KEY) {

257 return 0;

258 }

259

260 if (client.command) {

261 return client_command(ev);

262 }

263

264 if (ev.key == TB_KEY_ESC) {

265 client_reset();

266 return 0;

267 }

268

269 if (ev.ch >= (client.counter ? '0' : '1') && ev.ch <= '9') {

270 int i = ev.ch - '0';

271 client.g = 0;

272 if (client.counter >= 100000000) return 0;

273 if (client.counter == 0 && i == 0) return 0;

274 client.counter = client.counter * 10 + i;

275 return 0;

276 }

277

278 switch (ev.ch) {

279 case 'j':

280 ADDMAX(view->selected, AZ(client.counter), view->length - 1);

281 client.counter = 0;

282 break;

283 case 'k':

284 SUBMIN(client.view->selected, AZ(client.counter), 0);

285 client.counter = 0;

286 break;

287 case 'l':

288 view_open(view);

289 break;

290 case 'h':

291 {

292 char name[1024];

293 char *ptr = strrchr(view->path, '/');

294 if (!ptr)

295 break;

296 sstrcpy(name, ptr + 1);

297 if (file_up(view))

298 break;

299 file_ls(view);

300 view_select(view, name);

301 }

302 break;

303 case 'T':

304 case 't':

305 if (!client.g) break;

306 if (ev.ch == 'T') { /* backward */

307 if (view->prev) client.view = view->prev;

308 else {

309 while (view->next) view = view->next;

310 client.view = view;

311 }

312 } else { /* forward */

313 if (view->next) client.view = view->next;

314 else {

315 while (view->prev) view = view->prev;

316 client.view = view;

317 }

318 }

319 file_ls(client.view);

320 client_reset();

321 break;

322 case '.':

323 view->showhidden = !view->showhidden;

324 file_ls(view);

325 break;

326 case ':':

327 client.command = 1;

328 client.error = 0;

329 client_reset();

330 client.field[0] = ':';

331 client.field[1] = '\0';

332 break;

333 case 'e':

334 {

335 char buf[1024];

336 tb_shutdown();

337 snprintf(V(buf), "$EDITOR %s/%s", view->path, SELECTED(view));

338 system(buf);

339 tb_init();

340 }

341 break;

342 case 'G':

343 view->selected = view->length - 1;

344 break;

345 case 'g':

346 if (client.g) {

347 view->selected = 0;

348 client.g = 0;

349 break;

350 }

351 client.g = 1;

352 break;

353 }

354

355 return 0;

356 }

357