vis: let '^ mark point to top of jump list
[vis.git] / text.h
blobe76ad5b24b80c2f6f4305b8c253fcb496275ce09
1 #ifndef TEXT_H
2 #define TEXT_H
4 #include <stdbool.h>
5 #include <stdint.h>
6 #include <time.h>
7 #include <unistd.h>
8 #include <stdarg.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
12 /** A mark. */
13 typedef uintptr_t Mark;
15 /** An invalid mark, lookup of which will yield `EPOS`. */
16 #define EMARK ((Mark)0)
17 /** An invalid position. */
18 #define EPOS ((size_t)-1)
20 /** A range. */
21 typedef struct {
22 size_t start; /**< Absolute byte position. */
23 size_t end; /**< Absolute byte position. */
24 } Filerange;
26 /**
27 * Text object storing the buffer content being edited.
29 typedef struct Text Text;
30 typedef struct Piece Piece;
31 typedef struct TextSave TextSave;
33 /**
34 * Iterator used to navigate the buffer content.
36 * Captures the position within a Piece.
38 * @rst
39 * .. warning:: Any change to the Text will invalidate the iterator state.
40 * .. note:: Should be treated as an opaque type.
41 * @endrst
43 typedef struct {
44 const char *start; /**< Start of the piece data. */
45 const char *end; /**< End of piece data. Addressable range is ``[start, end)``. */
46 const char *text; /**< Current position within piece. Invariant ``start <= text < end`` holds. */
47 const Piece *piece; /**< Internal state of current piece. */
48 size_t pos; /**< Absolute position in bytes from start of buffer. */
49 } Iterator;
51 /**
52 * @defgroup load
53 * @{
55 /**
56 * Create a text instance populated with the given file content.
58 * @param filename The name of the file to load, if ``NULL`` an empty text is created.
59 * @return The new Text object or ``NULL`` in case of an error.
60 * @rst
61 * .. note:: When attempting to load a non-regular file, ``errno`` will be set to:
63 * - ``EISDIR`` for a directory.
64 * - ``ENOTSUP`` otherwise.
65 * @endrst
67 Text *text_load(const char *filename);
68 /** Release all ressources associated with this text instance. */
69 void text_free(Text*);
70 /**
71 * @}
72 * @defgroup state
73 * @{
75 /** Return the size in bytes of the whole text. */
76 size_t text_size(Text*);
77 /**
78 * Get file information at time of load or last save, whichever happened more
79 * recently.
80 * @rst
81 * .. note:: If an empty text instance was created using ``text_load(NULL)``
82 * and it has not yet been saved, an all zero ``struct stat`` will
83 * be returned.
84 * @endrst
85 * @return See ``stat(2)`` for details.
87 struct stat text_stat(Text*);
88 /** Query whether the text contains any unsaved modifications. */
89 bool text_modified(Text*);
90 /**
91 * @}
92 * @defgroup modify
93 * @{
95 /**
96 * Insert data at the given byte position.
98 * @param pos The absolute byte position.
99 * @param data The data to insert.
100 * @param len The length of the data in bytes.
101 * @return Whether the insertion succeeded.
103 bool text_insert(Text*, size_t pos, const char *data, size_t len);
105 * Delete data at given byte position.
107 * @param pos The absolute byte position.
108 * @param len The number of bytes to delete, starting from ``pos``.
109 * @return Whether the deletion succeeded.
111 bool text_delete(Text*, size_t pos, size_t len);
112 bool text_delete_range(Text*, Filerange*);
113 bool text_printf(Text*, size_t pos, const char *format, ...) __attribute__((format(printf, 3, 4)));
114 bool text_appendf(Text*, const char *format, ...) __attribute__((format(printf, 2, 3)));
116 * @}
117 * @defgroup history
118 * @{
121 * Create a text snapshot, that is a vertice in the history graph.
123 void text_snapshot(Text*);
125 * Revert to previous snapshot along the main branch.
126 * @rst
127 * .. note:: Takes an implicit snapshot.
128 * @endrst
129 * @return The position of the first change or ``EPOS``, if already at the
130 * oldest state i.e. there was nothing to undo.
132 size_t text_undo(Text*);
134 * Reapply an older change along the main brach.
135 * @rst
136 * .. note:: Takes an implicit snapshot.
137 * @endrst
138 * @return The position of the first change or ``EPOS``, if already at the
139 * newest state i.e. there was nothing to redo.
141 size_t text_redo(Text*);
142 size_t text_earlier(Text*);
143 size_t text_later(Text*);
145 * Restore the text to the state closest to the time given
147 size_t text_restore(Text*, time_t);
149 * Get creation time of current state.
150 * @rst
151 * .. note:: TODO: This is currently not the same as the time of the last snapshot.
152 * @endrst
154 time_t text_state(Text*);
156 * @}
157 * @defgroup lines
158 * @{
160 size_t text_pos_by_lineno(Text*, size_t lineno);
161 size_t text_lineno_by_pos(Text*, size_t pos);
164 * @}
165 * @defgroup access
166 * @{
169 * Get byte stored at ``pos``.
170 * @param pos The absolute position.
171 * @param byte Destination address to store the byte.
172 * @return Whether ``pos`` was valid and ``byte`` updated accordingly.
173 * @rst
174 * .. note:: Unlike :c:func:`text_iterator_byte_get()` this function does not
175 * return an artificial NUL byte at EOF.
176 * @endrst
178 bool text_byte_get(Text*, size_t pos, char *byte);
180 * Store at most `len` bytes starting from ``pos`` into ``buf``.
181 * @param pos The absolute starting position.
182 * @param len The length in bytes.
183 * @param buf The destination buffer.
184 * @return The number of bytes (``<= len``) stored at ``buf``.
185 * @rst
186 * .. warning:: ``buf`` will not be NUL terminated.
187 * @endrst
189 size_t text_bytes_get(Text*, size_t pos, size_t len, char *buf);
191 * Fetch text range into newly allocate memory region.
192 * @param pos The absolute starting position.
193 * @param len The length in bytes.
194 * @return A contigious NUL terminated buffer holding the requested range, or
195 * ``NULL`` in error case.
196 * @rst
197 * .. warning:: The returned pointer must be `free(3)`-ed by the caller.
198 * @endrst
200 char *text_bytes_alloc0(Text*, size_t pos, size_t len);
202 * @}
203 * @defgroup iterator
204 * @{
206 Iterator text_iterator_get(Text*, size_t pos);
207 bool text_iterator_valid(const Iterator*);
208 bool text_iterator_next(Iterator*);
209 bool text_iterator_prev(Iterator*);
211 * @}
212 * @defgroup iterator_byte
213 * @{
215 bool text_iterator_byte_get(Iterator*, char *b);
216 bool text_iterator_byte_prev(Iterator*, char *b);
217 bool text_iterator_byte_next(Iterator*, char *b);
218 bool text_iterator_byte_find_prev(Iterator*, char b);
219 bool text_iterator_byte_find_next(Iterator*, char b);
221 * @}
222 * @defgroup iterator_code
223 * @{
225 bool text_iterator_codepoint_next(Iterator *it, char *c);
226 bool text_iterator_codepoint_prev(Iterator *it, char *c);
228 * @}
229 * @defgroup iterator_char
230 * @{
232 bool text_iterator_char_next(Iterator*, char *c);
233 bool text_iterator_char_prev(Iterator*, char *c);
235 * @}
236 * @defgroup mark
237 * @{
240 * Set a mark.
241 * @rst
242 * .. note:: Setting a mark to `text_size` will always return the current text
243 * size upon lookup.
244 * @endrst
245 * @param pos The position at which to store the mark.
246 * @return The mark or `EMARK` if an invalid position was given.
248 Mark text_mark_set(Text*, size_t pos);
250 * Lookup a mark.
251 * @param mark The mark to look up.
252 * @return The byte position or `EPOS` for an invalid mark.
254 size_t text_mark_get(Text*, Mark);
256 * @}
257 * @defgroup save
258 * @{
261 * Save the whole text to the given file name.
263 bool text_save(Text*, const char *filename);
265 * Save a file range to the given file name.
267 bool text_save_range(Text*, Filerange*, const char *filename);
269 * Method used to save the text.
271 enum TextSaveMethod {
272 /** Automatically chose best option. */
273 TEXT_SAVE_AUTO,
275 * Save file atomically using `rename(2)`.
277 * Creates a new file named `filename~` and tries to restore all important
278 * meta data. After which it is atomically moved to its final
279 * (possibly already existing) destination using `rename(2)`.
281 * @rst
282 * .. warning:: This approach does not work if:
284 * - The file is a symbolic link.
285 * - The file is a hard link.
286 * - File ownership can not be preserved.
287 * - File group can not be preserved.
288 * - Directory permissions do not allow creation of a new file.
289 * - POSXI ACL can not be preserved (if enabled).
290 * - SELinux security context can not be preserved (if enabled).
291 * @endrst
293 TEXT_SAVE_ATOMIC,
295 * Overwrite file in place.
296 * @rst
297 * .. warning:: I/O failure might cause data loss.
298 * @endrst
300 TEXT_SAVE_INPLACE,
304 * Setup a sequence of write operations.
306 * The returned `TextSave` pointer can be used to write multiple, possibly
307 * non-contigious, file ranges.
308 * @rst
309 * .. warning:: For every call to `text_save_begin` there must be exactly
310 * one matching call to either `text_save_commit` or
311 * `text_save_cancel` to release the underlying resources.
312 * @endrst
314 TextSave *text_save_begin(Text*, const char *filename, enum TextSaveMethod);
316 * Write file range.
317 * @return The number of bytes written or ``-1`` in case of an error.
319 ssize_t text_save_write_range(TextSave*, Filerange*);
321 * Commit changes to disk.
322 * @return Whether changes have been saved.
323 * @rst
324 * .. note:: Releases the underlying resources and `free(3)`'s the given `TextSave`
325 * pointer which must no longer be used.
326 * @endrst
328 bool text_save_commit(TextSave*);
330 * Abort a save operation.
331 * @rst
332 * .. note:: Does not guarantee to undo the previous writes (they might have been
333 * performed in-place). However, it releases the underlying resources and
334 * `free(3)`'s the given `TextSave` pointer which must no longer be used.
335 * @endrst
337 void text_save_cancel(TextSave*);
339 * Write whole text content to file descriptor.
340 * @return The number of bytes written or ``-1`` in case of an error.
342 ssize_t text_write(Text*, int fd);
344 * Write file range to file descriptor.
345 * @return The number of bytes written or ``-1`` in case of an error.
347 ssize_t text_write_range(Text*, Filerange*, int fd);
349 * @}
350 * @defgroup misc
351 * @{
354 * Check whether ``ptr`` is part of a memory mapped region associated with
355 * this text instance.
357 bool text_mmaped(Text*, const char *ptr);
358 /** @} */
360 #endif