1 #include "buffer_manager.hh"
2
3 #include "assert.hh"
4 #include "buffer.hh"
5 #include "client_manager.hh"
6 #include "exception.hh"
7 #include "file.hh"
8 #include "ranges.hh"
9 #include "string.hh"
10
11 namespace Kakoune
12 {
13
~BufferManager()14 BufferManager::~BufferManager()
15 {
16 // Move buffers to avoid running BufClose with buffers remaining in that list
17 BufferList buffers = std::move(m_buffers);
18
19 for (auto& buffer : buffers)
20 buffer->on_unregistered();
21
22 // Make sure not clients exists
23 if (ClientManager::has_instance())
24 ClientManager::instance().clear(true);
25 }
26
create_buffer(String name,Buffer::Flags flags,BufferLines lines,ByteOrderMark bom,EolFormat eolformat,FsStatus fs_status)27 Buffer* BufferManager::create_buffer(String name, Buffer::Flags flags, BufferLines lines, ByteOrderMark bom, EolFormat eolformat, FsStatus fs_status)
28 {
29 auto path = real_path(parse_filename(name));
30 for (auto& buf : m_buffers)
31 {
32 if (buf->name() == name or
33 (buf->flags() & Buffer::Flags::File and buf->name() == path))
34 throw runtime_error{"buffer name is already in use"};
35 }
36
37 m_buffers.push_back(std::make_unique<Buffer>(std::move(name), flags, lines, bom, eolformat, fs_status));
38 auto* buffer = m_buffers.back().get();
39 buffer->on_registered();
40
41 if (contains(m_buffer_trash, buffer))
42 throw runtime_error{"buffer got removed during its creation"};
43
44 return buffer;
45 }
46
delete_buffer(Buffer & buffer)47 void BufferManager::delete_buffer(Buffer& buffer)
48 {
49 auto it = find_if(m_buffers, [&](auto& p) { return p.get() == &buffer; });
50 if (it == m_buffers.end()) // we might be trying to recursively delete this buffer
51 return;
52
53 m_buffer_trash.emplace_back(std::move(*it));
54 m_buffers.erase(it);
55
56 if (ClientManager::has_instance())
57 ClientManager::instance().ensure_no_client_uses_buffer(buffer);
58
59 buffer.on_unregistered();
60 }
61
get_buffer_ifp(StringView name)62 Buffer* BufferManager::get_buffer_ifp(StringView name)
63 {
64 auto path = real_path(parse_filename(name));
65 for (auto& buf : m_buffers)
66 {
67 if (buf->name() == name or
68 (buf->flags() & Buffer::Flags::File and buf->name() == path))
69 return buf.get();
70 }
71 return nullptr;
72 }
73
get_buffer(StringView name)74 Buffer& BufferManager::get_buffer(StringView name)
75 {
76 Buffer* res = get_buffer_ifp(name);
77 if (not res)
78 throw runtime_error{format("no such buffer '{}'", name)};
79 return *res;
80 }
81
get_first_buffer()82 Buffer& BufferManager::get_first_buffer()
83 {
84 if (all_of(m_buffers, [](auto& b) { return (b->flags() & Buffer::Flags::Debug); }))
85 create_buffer("*scratch*", Buffer::Flags::None,
86 {StringData::create({"*** this is a *scratch* buffer which won't be automatically saved ***\n"}),
87 StringData::create({"*** use it for notes or open a file buffer with the :edit command ***\n"})},
88 ByteOrderMark::None, EolFormat::Lf, {InvalidTime, {}, {}});
89
90 return *m_buffers.back();
91 }
92
backup_modified_buffers()93 void BufferManager::backup_modified_buffers()
94 {
95 for (auto& buf : m_buffers)
96 {
97 if ((buf->flags() & Buffer::Flags::File) and buf->is_modified()
98 and not (buf->flags() & Buffer::Flags::ReadOnly))
99 write_buffer_to_backup_file(*buf);
100 }
101 }
102
clear_buffer_trash()103 void BufferManager::clear_buffer_trash()
104 {
105 m_buffer_trash.clear();
106 }
107
arrange_buffers(ConstArrayView<String> first_ones)108 void BufferManager::arrange_buffers(ConstArrayView<String> first_ones)
109 {
110 Vector<size_t> indices;
111 for (const auto& name : first_ones)
112 {
113 auto it = find_if(m_buffers, [&](auto& buf) { return buf->name() == name or buf->display_name() == name; });
114 if (it == m_buffers.end())
115 throw runtime_error{format("no such buffer '{}'", name)};
116 size_t index = it - m_buffers.begin();
117 if (contains(indices, index))
118 throw runtime_error{format("buffer '{}' appears more than once", name)};
119 indices.push_back(index);
120 }
121
122 BufferList res;
123 for (size_t index : indices)
124 res.push_back(std::move(m_buffers[index]));
125 for (auto& buf : m_buffers)
126 {
127 if (buf)
128 res.push_back(std::move(buf));
129 }
130 m_buffers = std::move(res);
131 }
132
133 }
134