GitHub

@@ -0,0 +1,180 @@

1+

/*

2+

** mirb_history.c - Command history for mirb editor

3+

**

4+

** See Copyright Notice in mruby.h

5+

*/

6+7+

#include "mirb_history.h"

8+

#include <stdio.h>

9+

#include <stdlib.h>

10+

#include <string.h>

11+12+

/*

13+

* Initialize history

14+

*/

15+

mrb_bool

16+

mirb_history_init(mirb_history *hist, size_t capacity)

17+

{

18+

memset(hist, 0, sizeof(*hist));

19+20+

if (capacity == 0) capacity = MIRB_HISTORY_SIZE;

21+22+

hist->entries = (char**)calloc(capacity, sizeof(char*));

23+

if (hist->entries == NULL) return FALSE;

24+25+

hist->capacity = capacity;

26+

hist->count = 0;

27+

hist->start = 0;

28+

hist->pos = 0;

29+

hist->saved_input = NULL;

30+

hist->browsing = FALSE;

31+32+

return TRUE;

33+

}

34+35+

/*

36+

* Free history resources

37+

*/

38+

void

39+

mirb_history_free(mirb_history *hist)

40+

{

41+

if (hist->entries) {

42+

for (size_t i = 0; i < hist->capacity; i++) {

43+

free(hist->entries[i]);

44+

}

45+

free(hist->entries);

46+

hist->entries = NULL;

47+

}

48+

free(hist->saved_input);

49+

hist->saved_input = NULL;

50+

hist->count = 0;

51+

hist->capacity = 0;

52+

}

53+54+

/*

55+

* Get actual index in circular buffer

56+

*/

57+

static size_t

58+

actual_index(mirb_history *hist, size_t logical_idx)

59+

{

60+

return (hist->start + logical_idx) % hist->capacity;

61+

}

62+63+

/*

64+

* Add entry to history

65+

*/

66+

void

67+

mirb_history_add(mirb_history *hist, const char *entry)

68+

{

69+

if (entry == NULL || entry[0] == '\0') return;

70+71+

/* Don't add if same as last entry */

72+

if (hist->count > 0) {

73+

size_t last_idx = actual_index(hist, hist->count - 1);

74+

if (strcmp(hist->entries[last_idx], entry) == 0) {

75+

return;

76+

}

77+

}

78+79+

char *copy = strdup(entry);

80+

if (copy == NULL) return;

81+82+

if (hist->count < hist->capacity) {

83+

/* Still have room */

84+

size_t idx = actual_index(hist, hist->count);

85+

hist->entries[idx] = copy;

86+

hist->count++;

87+

}

88+

else {

89+

/* Buffer is full, overwrite oldest */

90+

size_t idx = hist->start;

91+

free(hist->entries[idx]);

92+

hist->entries[idx] = copy;

93+

hist->start = (hist->start + 1) % hist->capacity;

94+

}

95+96+

/* Reset browsing state */

97+

hist->browsing = FALSE;

98+

hist->pos = hist->count;

99+

}

100+101+

/*

102+

* Start browsing history

103+

*/

104+

void

105+

mirb_history_browse_start(mirb_history *hist, const char *current_input)

106+

{

107+

if (hist->browsing) return;

108+109+

free(hist->saved_input);

110+

hist->saved_input = current_input ? strdup(current_input) : NULL;

111+

hist->browsing = TRUE;

112+

hist->pos = hist->count; /* Start past the end (at current input) */

113+

}

114+115+

/*

116+

* Stop browsing history

117+

*/

118+

void

119+

mirb_history_browse_stop(mirb_history *hist)

120+

{

121+

free(hist->saved_input);

122+

hist->saved_input = NULL;

123+

hist->browsing = FALSE;

124+

hist->pos = hist->count;

125+

}

126+127+

/*

128+

* Get previous entry (older)

129+

*/

130+

const char *

131+

mirb_history_prev(mirb_history *hist)

132+

{

133+

if (hist->count == 0) return NULL;

134+135+

if (!hist->browsing) {

136+

/* Should call browse_start first, but handle gracefully */

137+

hist->browsing = TRUE;

138+

hist->pos = hist->count;

139+

}

140+141+

if (hist->pos == 0) {

142+

/* Already at oldest entry */

143+

return NULL;

144+

}

145+146+

hist->pos--;

147+

return hist->entries[actual_index(hist, hist->pos)];

148+

}

149+150+

/*

151+

* Get next entry (newer)

152+

*/

153+

const char *

154+

mirb_history_next(mirb_history *hist)

155+

{

156+

if (!hist->browsing) return NULL;

157+158+

if (hist->pos >= hist->count) {

159+

/* Already at current input */

160+

return NULL;

161+

}

162+163+

hist->pos++;

164+165+

if (hist->pos >= hist->count) {

166+

/* Moved past newest entry, return saved input */

167+

return hist->saved_input ? hist->saved_input : "";

168+

}

169+170+

return hist->entries[actual_index(hist, hist->pos)];

171+

}

172+173+

/*

174+

* Get current entry count

175+

*/

176+

size_t

177+

mirb_history_count(mirb_history *hist)

178+

{

179+

return hist->count;

180+

}

Read the original on github.com ↗