#include "write.h" #include #include #include namespace { struct write_t { struct request_t { int fd; std::string str; }; WATCH_LEAKS(write_t); write_t (int fd, std::string const& str); virtual ~write_t (); static int handle_request (write_t::request_t const& request); void handle_reply (int error); private: size_t client_key; }; static oak::server_t& server () { static oak::server_t instance; return instance; } write_t::write_t (int fd, std::string const& str) { client_key = server().register_client(this); int newFd = dup(fd); fcntl(newFd, F_SETFD, FD_CLOEXEC); server().send_request(client_key, (request_t){ newFd, str }); } write_t::~write_t () { server().unregister_client(client_key); } int write_t::handle_request (write_t::request_t const& request) { bool success = write(request.fd, request.str.data(), request.str.size()) == request.str.size(); close(request.fd); return success ? 0 : errno; } void write_t::handle_reply (int error) { delete this; } } namespace ng { static size_t count_columns (buffer_t const& buffer, index_t caret, size_t tabSize) { std::string const str = buffer.substr(buffer.begin(buffer.convert(caret.index).line), caret.index); size_t len = 0; citerate(ch, diacritics::make_range(str.data(), str.data() + str.size())) len += *ch == '\t' ? tabSize - (len % tabSize) : (text::is_east_asian_width(*ch) ? 2 : 1); return len + caret.carry; } text::range_t write_unit_to_fd (buffer_t const& buffer, range_t const& range, size_t tabSize, int fd, input::type unit, input::type fallbackUnit, input_format::type format, scope::selector_t const& scopeSelector, std::map& variables, bool* inputWasSelection) // TODO Move write_unit_to_fd to command framework. { input::type actualUnit = unit == input::selection && range.empty() ? fallbackUnit : unit; *inputWasSelection = actualUnit == input::selection; range_t r; switch(actualUnit) { case input::character: r = extend_if_empty(buffer, range, kSelectionExtendRight).last(); break; case input::word: r = extend_if_empty(buffer, range, kSelectionExtendToWord).last(); break; case input::line: r = extend_if_empty(buffer, range, kSelectionExtendToLineExclLF).last(); break; case input::scope: r = select_scope(buffer, range, scopeSelector).last(); break; case input::selection: r = range; break; case input::entire_document: r = extend(buffer, range, kSelectionExtendToAll).last(); break; }; if(!r.empty()) { std::string str = ""; bool first = true; citerate(range, dissect_columnar(buffer, r)) { if(!first) str += "\n"; str += format == input_format::xml ? to_xml(buffer, range->min().index, range->max().index) : buffer.substr(range->min().index, range->max().index); first = false; } new write_t(fd, str); } close(fd); if(r && actualUnit != input::entire_document) { text::pos_t const& pos = buffer.convert(r.min().index); variables.insert(std::make_pair("TM_INPUT_START_LINE", std::to_string(pos.line + 1))); variables.insert(std::make_pair("TM_INPUT_START_LINE_INDEX", std::to_string(pos.column))); variables.insert(std::make_pair("TM_INPUT_START_COLUMN", std::to_string(count_columns(buffer, r.min(), tabSize) + 1))); } return text::range_t(buffer.convert(r.min().index), buffer.convert(r.max().index)); } } /* ng */