💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › b4b1a06acf1bc909e364cfab429eb… captured on 2023-12-28 at 15:43:24. Gemini links have been rewritten to link to archived content

View Raw

More Information

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

Go Back

0 /*

1 * ISC License

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

3 */

4 #include <stdio.h>

5 #include <stdlib.h>

6 #include <string.h>

7 #include <stdint.h>

8 #include "macro.h"

9 #include "strlcpy.h"

10 #include "utf8.h"

11 #include "termbox.h"

12 #include "gemini.h"

13 #include "page.h"

14 #include "request.h"

15 #include "client.h"

16 #include "commands.h"

17 #include "tab.h"

18 #include "error.h"

19 #include "parser.h"

20

21 void client_enter_mode_cmdline(struct client *client) {

22 client->count = 0;

23 client->error = 0;

24 memset(client->cmd, 0, sizeof(client->cmd));

25 client->mode = MODE_CMDLINE;

26 client->cursor = STRLCPY(client->cmd, ":");

27 }

28

29 static void refresh_search(struct client *client) {

30 struct request *req;

31 if (client->cmd[0] != '/') return;

32 STRLCPY(client->search, &client->cmd[1]);

33 if (!(req = tab_completed(client->tab))) return;

34 page_search(&req->page, client->search);

35 req->scroll = page_selection_line(req->page);

36 req->scroll -= client_display_rect(client).h / 2;

37 tab_scroll(client->tab, 0, client_display_rect(client));

38 }

39

40 int handle_cmd(struct client *client) {

41

42 const char invalid[] = "Invalid command: %s";

43 char name[MAX_CMD_NAME], cmd[MAX_CMDLINE - sizeof(invalid)];

44 size_t i;

45 int number;

46

47 ASSERT(sizeof(cmd) > sizeof(name))

48

49 STRLCPY(cmd, &client->cmd[1]);

50

51 number = atoi(cmd);

52 if (number || !STRCMP(cmd, "0")) {

53 struct request *req;

54 if (!client->tab) return 0;

55 req = tab_completed(client->tab);

56 if (!req) return 0;

57 req->scroll = number;

58 request_scroll(req, 0, client_display_rect(client));

59 return 0;

60 }

61

62 for (i = 0; i < sizeof(name); ) {

63 char c = cmd[i];

64 size_t len;

65 if (c == ' ' || c == '\t' || c == '\0') {

66 name[i] = '\0';

67 break;

68 }

69 len = i + utf8_char_length(cmd[i]);

70 for (; i < len; i++)

71 name[i] = cmd[i];

72 }

73 for (i = 0; i < LENGTH(commands); i++) {

74 int j;

75 if (STRCMP(commands[i].name, name)) continue;

76 j = strnlen(V(commands[i].name));

77 for (; cmd[j] && WHITESPACE(cmd[j]); j++) ;

78 if (commands[i].command(client, &cmd[j], sizeof(cmd) - j))

79 return 1;

80 return 0;

81 }

82 client->error = 1;

83 snprintf(V(client->cmd), invalid, cmd);

84 return 0;

85 }

86

87 int client_input_cmdline(struct client *client, struct tb_event ev) {

88

89 int len, prefix;

90 struct request *req;

91 int search_mode = client->cmd[0] == '/';

92

93 req = tab_input(client->tab);

94

95 if (req) {

96 prefix = strnlen(V(req->meta)) + 2;

97 if (client->cursor < prefix) client->cursor = prefix;

98 } else prefix = 1;

99

100 switch (ev.key) {

101 case TB_KEY_ESC:

102 client->mode = MODE_NORMAL;

103 if (req) req->state = STATE_ENDED;

104 return 0;

105 case TB_KEY_ENTER:

106 if (search_mode) ;

107 else if (req) {

108 char url[2048];

109 int error;

110 req->state = STATE_ENDED;

111 len = snprintf(V(url), "%s?%s", req->url,

112 client->tab->input);

113 error = len >= MAX_URL ?

114 ERROR_URL_TOO_LONG :

115 tab_request(client->tab, url);

116 if (error) {

117 client->tab->failure = 1;

118 error_string(error, V(client->tab->error));

119 }

120 } else if (handle_cmd(client)) return 1;

121 client->mode = MODE_NORMAL;

122 return 0;

123 case TB_KEY_BACKSPACE:

124 case TB_KEY_BACKSPACE2:

125 if (client->cursor <= prefix) {

126 if (!req) client->mode = MODE_NORMAL;

127 return 0;

128 }

129 if (!req) {

130 client->cursor = utf8_previous(client->cmd,

131 client->cursor);

132 client->cmd[client->cursor] = 0;

133 refresh_search(client);

134 return 0;

135 }

136 client->cursor = utf8_previous(client->tab->input,

137 client->cursor - prefix) + prefix;

138 client->tab->input[client->cursor - prefix] = 0;

139 goto rewrite;

140 }

141

142 if (!ev.ch) return 0;

143

144 len = utf8_unicode_length(ev.ch);

145 if ((size_t)(client->cursor + len) >= sizeof(client->cmd)) return 0;

146

147 if (!req) {

148 len = utf8_unicode_to_char(

149 &client->cmd[client->cursor], ev.ch);

150 client->cursor += len;

151 client->cmd[client->cursor] = '\0';

152 refresh_search(client);

153 return 0;

154 }

155

156 len = utf8_unicode_to_char(

157 &client->tab->input[client->cursor - prefix], ev.ch);

158 client->cursor += len;

159 client->tab->input[client->cursor - prefix] = '\0';

160 rewrite:

161 if (req->status == GMI_INPUT) {

162 strlcpy(&client->cmd[prefix], client->tab->input,

163 sizeof(client->cmd) - prefix);

164 } else if (req->status == GMI_SECRET) {

165 int i = 0;

166 size_t j;

167 for (j = prefix; j < sizeof(client->cmd) &&

168 client->tab->input[i]; j++) {

169 i += utf8_char_length(client->tab->input[i]);

170 client->cmd[j] = '*';

171 }

172 client->cmd[j] = '\0';

173 }

174

175 return 0;

176 }

177