1 /*
2  * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_UTILS_INPUTBUFFER_H_
8 #define _FCITX_UTILS_INPUTBUFFER_H_
9 
10 #include <cstring>
11 #include <memory>
12 #include <string>
13 #include <fcitx-utils/flags.h>
14 #include <fcitx-utils/macros.h>
15 #include "fcitxutils_export.h"
16 
17 /// \addtogroup FcitxUtils
18 /// \{
19 /// \file
20 /// \brief Generic InputBuffer to be used to handle user's preedit.
21 
22 namespace fcitx {
23 class InputBufferPrivate;
24 
25 enum class InputBufferOption {
26     /// No option.
27     NoOption = 0,
28     /// The input buffer is ascii character only, non ascii char will raise
29     /// exception.
30     AsciiOnly = 1,
31     /// Whether the input buffer only supports cursor at the end of buffer.
32     FixedCursor = 1 << 1
33 };
34 
35 using InputBufferOptions = Flags<InputBufferOption>;
36 
37 /// A string buffer that come with convinient functions to handle use input.
38 class FCITXUTILS_EXPORT InputBuffer {
39 public:
40     /// Create a input buffer with options.
41     /// \see InputBufferOption
42     InputBuffer(InputBufferOptions options = InputBufferOption::NoOption);
43     virtual ~InputBuffer();
44 
45     /// Get the buffer option.
46     InputBufferOptions options() const;
47 
48     /// Type a C-String with length into buffer.
type(const char * s,size_t length)49     bool type(const char *s, size_t length) { return typeImpl(s, length); }
50     /// Type an std::stirng to buffer.
type(const std::string & s)51     bool type(const std::string &s) { return type(s.c_str(), s.size()); }
52     /// Type a C-String to buffer.
type(const char * s)53     bool type(const char *s) { return type(s, std::strlen(s)); }
54     /// Type a ucs4 character to buffer.
55     bool type(uint32_t unicode);
56 
57     /// Erase a range of character.
58     virtual void erase(size_t from, size_t to);
59     /// Set cursor position, by character.
60     virtual void setCursor(size_t cursor);
61 
62     /// Get the max size of the buffer.
63     size_t maxSize() const;
64 
65     /// Set max size of the buffer.
66     void setMaxSize(size_t s);
67 
68     /// Utf8 string in the buffer.
69     const std::string &userInput() const;
70 
71     /// Cursor position by utf8 character.
72     size_t cursor() const;
73 
74     /// Cursor position by char (byte).
75     size_t cursorByChar() const;
76 
77     /// Size of buffer, by number of utf8 character.
78     size_t size() const;
79 
80     /// UCS-4 char in the buffer. Will raise exception if i is out of range.
81     uint32_t charAt(size_t i) const;
82 
83     /// Byte range for character at position i.
84     std::pair<size_t, size_t> rangeAt(size_t i) const;
85 
86     /// Byte size at position i.
87     size_t sizeAt(size_t i) const;
88 
89     /// Whether buffer is empty.
empty()90     bool empty() const { return size() == 0; }
91 
92     /// Helper function to implement "delete" key.
del()93     inline bool del() {
94         auto c = cursor();
95         if (c < size()) {
96             erase(c, c + 1);
97             return true;
98         }
99         return false;
100     }
101 
102     /// Helper function to implement "backspace" key.
backspace()103     inline bool backspace() {
104         auto c = cursor();
105         if (c > 0) {
106             erase(c - 1, c);
107             return true;
108         }
109         return false;
110     }
111 
112     /// Clear all buffer.
clear()113     void clear() { erase(0, size()); }
114 
115     /// Save memory by call shrink to fit to internal buffer.
116     void shrinkToFit();
117 
118 protected:
119     /// Type a certain length of utf8 character to the buffer. [s, s+length]
120     /// need to be valid utf8 string.
121     virtual bool typeImpl(const char *s, size_t length);
122 
123 private:
124     std::unique_ptr<InputBufferPrivate> d_ptr;
125     FCITX_DECLARE_PRIVATE(InputBuffer);
126 };
127 } // namespace fcitx
128 
129 #endif // _FCITX_UTILS_INPUTBUFFER_H_
130