mirror of
https://github.com/textmate/textmate.git
synced 2026-01-23 05:37:55 -05:00
When opening SCM manager folder TM opens untitled document in the editor area and the target folder in file browser. When one sets `windowTitle` to display SCM branch this is not displayed for untitled document. So one needs to open some existing file first. This change sets SCM variables also for untitled document as if it was saved in selected file browser folder, effectively showing current SCM branch.
391 lines
16 KiB
C++
391 lines
16 KiB
C++
#ifndef DOCUMENT_H_MIJOONQT
|
|
#define DOCUMENT_H_MIJOONQT
|
|
|
|
#include <buffer/buffer.h>
|
|
#include <undo/undo.h>
|
|
#include <parse/grammar.h>
|
|
#include <plist/uuid.h>
|
|
#include <plist/date.h>
|
|
#include <settings/settings.h>
|
|
#include <text/types.h>
|
|
#include <authorization/authorization.h>
|
|
#include <file/bytes.h>
|
|
#include <file/open.h>
|
|
#include <file/save.h>
|
|
#include <file/encoding.h>
|
|
#include <scope/scope.h>
|
|
#include <oak/debug.h>
|
|
|
|
namespace document
|
|
{
|
|
struct watch_t;
|
|
struct document_t;
|
|
typedef std::shared_ptr<watch_t> watch_ptr;
|
|
typedef std::shared_ptr<document_t> document_ptr;
|
|
typedef std::shared_ptr<document_t const> document_const_ptr;
|
|
typedef std::weak_ptr<document_t> document_weak_ptr;
|
|
|
|
struct PUBLIC open_callback_t : file::open_callback_t
|
|
{
|
|
virtual ~open_callback_t () { }
|
|
virtual void show_content (std::string const& path, io::bytes_ptr content, std::map<std::string, std::string> const& attributes, std::string const& pathAttributes, std::string const& fileType, encoding::type const& encoding, std::vector<oak::uuid_t> const& binaryImportFilters, std::vector<oak::uuid_t> const& textImportFilters) { }
|
|
virtual void show_document (std::string const& path, document_ptr document) = 0;
|
|
virtual void show_error (std::string const& path, document_ptr document, std::string const& message, oak::uuid_t const& filter) = 0;
|
|
virtual void show_error (std::string const& path, std::string const& message, oak::uuid_t const& filter) { }
|
|
};
|
|
|
|
typedef std::shared_ptr<open_callback_t> open_callback_ptr;
|
|
|
|
struct PUBLIC save_callback_t : file::save_callback_t
|
|
{
|
|
virtual ~save_callback_t () { }
|
|
virtual void did_save_document (document_ptr document, std::string const& path, bool success, std::string const& message, oak::uuid_t const& filter) = 0;
|
|
virtual void did_save (std::string const& path, io::bytes_ptr content, std::string const& pathAttributes, encoding::type const& encoding, bool success, std::string const& message, oak::uuid_t const& filter) { }
|
|
};
|
|
|
|
typedef std::shared_ptr<save_callback_t> save_callback_ptr;
|
|
|
|
struct PUBLIC document_t : std::enable_shared_from_this<document_t>
|
|
{
|
|
WATCH_LEAKS(document_t);
|
|
|
|
document_t () : _did_load_marks(false), _selection(NULL_STR), _folded(NULL_STR), _visible_rect(NULL_STR), _disable_callbacks(false), _revision(0), _disk_revision(0), _modified(false), _path(NULL_STR), _open_count(0), _has_lru(false), _is_on_disk(false), _recent_tracking(true), _backup_path(NULL_STR), _backup_revision(0), _virtual_path(NULL_STR), _custom_name(NULL_STR), _untitled_count(0), _grammar_callback(*this), _file_type(NULL_STR), _path_attributes(NULL_STR), /*_folder(NULL_STR),*/ _disk_encoding(NULL_STR), _disk_newlines(NULL_STR), _disk_bom(false) { }
|
|
~document_t ();
|
|
|
|
bool operator== (document_t const& rhs) const { return _identifier == rhs._identifier; }
|
|
bool operator!= (document_t const& rhs) const { return _identifier != rhs._identifier; }
|
|
|
|
// ============================================================
|
|
// = Doing one-pass reading of file (find in arbitrary files) =
|
|
// ============================================================
|
|
|
|
struct reader_t { virtual io::bytes_ptr next () = 0; virtual ~reader_t () { } };
|
|
typedef std::shared_ptr<reader_t> reader_ptr;
|
|
reader_ptr create_reader () const;
|
|
|
|
// ======================================================
|
|
// = Performing replacements (from outside a text view) =
|
|
// ======================================================
|
|
|
|
void replace (std::multimap<text::range_t, std::string> const& replacements);
|
|
|
|
// ===================================================================
|
|
// = Controlling marks (bookmarks, warnings, errors, search matches) =
|
|
// ===================================================================
|
|
|
|
struct mark_t
|
|
{
|
|
WATCH_LEAKS(document_t::mark_t);
|
|
|
|
mark_t (char const* type = "bookmark") : type(type), info("") { }
|
|
mark_t (std::string const& type, std::string const& info = "") : type(type), info(info) { }
|
|
bool operator== (mark_t const& rhs) const { return type == rhs.type && info == rhs.info; }
|
|
bool operator!= (mark_t const& rhs) const { return type != rhs.type || info != rhs.info; }
|
|
std::string type, info;
|
|
};
|
|
|
|
void add_mark (text::range_t const& range, mark_t const& mark = mark_t());
|
|
void remove_all_marks (std::string const& typeToClear = NULL_STR);
|
|
std::multimap<text::range_t, mark_t> marks () const;
|
|
|
|
private:
|
|
void load_marks (std::string const& src) const;
|
|
void setup_marks (std::string const& src, ng::buffer_t& buf) const;
|
|
std::string marks_as_string () const;
|
|
mutable std::multimap<text::range_t, mark_t> _marks;
|
|
mutable bool _did_load_marks;
|
|
|
|
std::string _selection;
|
|
std::string _folded;
|
|
std::string _visible_rect;
|
|
io::bytes_ptr _content;
|
|
|
|
// ===============
|
|
// = Symbol list =
|
|
// ===============
|
|
public:
|
|
std::map<text::pos_t, std::string> symbols ();
|
|
|
|
// ===================
|
|
// = Callback system =
|
|
// ===================
|
|
|
|
struct callback_t
|
|
{
|
|
WATCH_LEAKS(document_t::callback_t);
|
|
|
|
enum event_t
|
|
{
|
|
did_save,
|
|
|
|
did_change_open_status,
|
|
did_change_modified_status,
|
|
did_change_on_disk_status,
|
|
did_change_path,
|
|
did_change_file_type,
|
|
did_change_indent_settings,
|
|
// did_change_display_name,
|
|
did_change_marks,
|
|
// did_change_symbols,
|
|
};
|
|
|
|
virtual ~callback_t () { }
|
|
virtual void handle_document_event (document_ptr document, event_t event) = 0;
|
|
};
|
|
|
|
void add_callback (callback_t* callback) { _callbacks.add(callback); }
|
|
void remove_callback (callback_t* callback) { _callbacks.remove(callback); }
|
|
|
|
private:
|
|
void check_modified (ssize_t diskRev, ssize_t rev);
|
|
|
|
void broadcast (callback_t::event_t event, bool cascade = true)
|
|
{
|
|
if(_disable_callbacks)
|
|
return;
|
|
|
|
_disable_callbacks = !cascade;
|
|
_callbacks(&callback_t::handle_document_event, shared_from_this(), event);
|
|
_disable_callbacks = false;
|
|
}
|
|
|
|
oak::callbacks_t<callback_t> _callbacks;
|
|
bool _disable_callbacks;
|
|
|
|
// ===================
|
|
// = For OakTextView =
|
|
// ===================
|
|
|
|
void post_load (std::string const& path, io::bytes_ptr content, std::map<std::string, std::string> const& attributes, std::string const& fileType, std::string const& pathAttributes, encoding::type const& encoding);
|
|
|
|
struct open_callback_wrapper_t : file::open_callback_t
|
|
{
|
|
open_callback_wrapper_t (document::document_ptr doc, document::open_callback_ptr callback) : _document(doc), _callbacks(1, callback) { }
|
|
|
|
void select_charset (std::string const& path, io::bytes_ptr content, file::open_context_ptr context) { _callbacks[0]->select_charset(path, content, context); }
|
|
void select_line_feeds (std::string const& path, io::bytes_ptr content, file::open_context_ptr context) { _callbacks[0]->select_line_feeds(path, content, context); }
|
|
void select_file_type (std::string const& path, io::bytes_ptr content, file::open_context_ptr context) { if(_document->file_type() == NULL_STR) _callbacks[0]->select_file_type(path, content, context); else context->set_file_type(_document->file_type()); }
|
|
void add_callback (document::open_callback_ptr callback) { _callbacks.push_back(callback); }
|
|
|
|
void show_content (std::string const& path, io::bytes_ptr content, std::map<std::string, std::string> const& attributes, std::string const& fileType, std::string const& pathAttributes, encoding::type const& encoding, std::vector<oak::uuid_t> const& binaryImportFilters, std::vector<oak::uuid_t> const& textImportFilters)
|
|
{
|
|
// we are deleted in post_load() so make a copy of relevant data
|
|
std::vector<document::open_callback_ptr> callbacks(_callbacks);
|
|
document::document_ptr doc = _document;
|
|
|
|
_document->post_load(path, content, attributes, fileType, pathAttributes, encoding);
|
|
iterate(cb, callbacks)
|
|
(*cb)->show_document(path, doc);
|
|
}
|
|
|
|
void show_error (std::string const& path, std::string const& message, oak::uuid_t const& filter)
|
|
{
|
|
// we are deleted in post_load() so make a copy of relevant data
|
|
std::vector<document::open_callback_ptr> callbacks(_callbacks);
|
|
document::document_ptr doc = _document;
|
|
|
|
_document->post_load(path, io::bytes_ptr(), std::map<std::string, std::string>(), NULL_STR, NULL_STR, encoding::type());
|
|
iterate(cb, callbacks)
|
|
(*cb)->show_error(path, doc, message, filter);
|
|
}
|
|
|
|
private:
|
|
document::document_ptr _document;
|
|
std::vector<document::open_callback_ptr> _callbacks;
|
|
};
|
|
|
|
typedef std::shared_ptr<open_callback_wrapper_t> open_callback_wrapper_ptr;
|
|
open_callback_wrapper_ptr _open_callback;
|
|
|
|
void post_save (std::string const& path, io::bytes_ptr content, std::string const& pathAttributes, encoding::type const& encoding, bool succes);
|
|
|
|
public:
|
|
bool try_open (document::open_callback_ptr callback);
|
|
void open ();
|
|
void close ();
|
|
|
|
void show ();
|
|
void hide ();
|
|
oak::date_t const& lru () const;
|
|
|
|
void try_save (document::save_callback_ptr callback);
|
|
bool save ();
|
|
bool backup ();
|
|
|
|
void set_path (std::string const& newPath);
|
|
void set_virtual_path (std::string const& virtualPath) { _virtual_path = virtualPath; }
|
|
void set_custom_name (std::string const& newCustomName) { _custom_name = newCustomName; }
|
|
void set_file_type (std::string const& newFileType);
|
|
|
|
std::string path () const { return _path; }
|
|
std::string virtual_path () const { return _virtual_path == NULL_STR ? _path : _virtual_path; }
|
|
std::string backup_path () const;
|
|
std::string display_name () const;
|
|
|
|
void set_disk_encoding (encoding::type const& encoding) { _disk_newlines = encoding.newlines(); _disk_encoding = encoding.charset(); _disk_bom = encoding.byte_order_mark(); }
|
|
encoding::type disk_encoding () const { return encoding::type(_disk_newlines, _disk_encoding, _disk_bom); }
|
|
|
|
encoding::type encoding_for_save_as_path (std::string const& path);
|
|
|
|
bool recent_tracking () const { return _recent_tracking && _path != NULL_STR; }
|
|
void set_recent_tracking (bool flag) { _recent_tracking = flag; }
|
|
|
|
ng::buffer_t& buffer () { ASSERT(_buffer); return *_buffer; }
|
|
ng::buffer_t const& buffer () const { ASSERT(_buffer); return *_buffer; }
|
|
|
|
ng::undo_manager_t& undo_manager () { ASSERT(_undo_manager); return *_undo_manager; }
|
|
ng::undo_manager_t const& undo_manager () const { ASSERT(_undo_manager); return *_undo_manager; }
|
|
|
|
// =============
|
|
// = Accessors =
|
|
// =============
|
|
|
|
oak::uuid_t identifier () const { return _identifier; }
|
|
ssize_t revision () const { return _revision; }
|
|
void set_revision (ssize_t rev) { check_modified(_disk_revision, rev); }
|
|
bool is_open () const { return _open_count != 0 && !_open_callback; }
|
|
|
|
std::string file_type () const;
|
|
std::string path_attributes () const { return _path_attributes; }
|
|
scope::scope_t scope () const { return file_type() + " " + path_attributes(); }
|
|
|
|
settings_t const settings (std::string const& untitledPath = NULL_STR) const
|
|
{
|
|
return settings_for_path(virtual_path(), scope(), path::parent(_path), identifier(), variables(std::map<std::string, std::string>(), false, untitledPath));
|
|
}
|
|
|
|
std::map<std::string, std::string> variables (std::map<std::string, std::string> map, bool sourceFileSystem = true, std::string const& untitledPath = NULL_STR) const;
|
|
|
|
bool is_modified () const;
|
|
bool is_on_disk () const { return is_open() ? _is_on_disk : path::exists(path()); }
|
|
void set_disk_revision (ssize_t rev) { check_modified(rev, _revision); }
|
|
std::string const& selection () const { return _selection; }
|
|
std::string const& folded () const { return _folded; }
|
|
std::string visible_rect () const { return _visible_rect; }
|
|
|
|
void set_selection (std::string const& sel) { _selection = sel; _visible_rect = NULL_STR; }
|
|
void set_folded (std::string const& folded) { _folded = folded; }
|
|
void set_visible_rect (std::string const& rect) { _visible_rect = rect; }
|
|
|
|
void set_authorization (osx::authorization_t const& auth) { _authorization = auth; }
|
|
|
|
private:
|
|
void setup_buffer ();
|
|
void grammar_did_change ();
|
|
|
|
void set_content (io::bytes_ptr const& bytes);
|
|
std::string content () const { ASSERT(_buffer); return _buffer->substr(0, _buffer->size()); }
|
|
|
|
void set_modified (bool flag);
|
|
|
|
// ==============
|
|
// = Properties =
|
|
// ==============
|
|
|
|
friend document_ptr create (std::string const& path);
|
|
friend document_ptr from_content (std::string const& content, std::string const& fileType);
|
|
friend document_ptr find (oak::uuid_t const& uuid, bool searchBackups);
|
|
|
|
oak::uuid_t _identifier; // to identify this document when there is no path
|
|
path::identifier_t _key;
|
|
ssize_t _revision;
|
|
ssize_t _disk_revision;
|
|
bool _modified;
|
|
|
|
std::string _path; // does not imply there actually is a file
|
|
size_t _open_count; // document open in some window/tab
|
|
mutable oak::date_t _lru; // last time document was shown
|
|
mutable bool _has_lru;
|
|
bool _is_on_disk;
|
|
bool _recent_tracking;
|
|
|
|
mutable std::string _backup_path; // if there is a backup, this is set — we can have a backup even when there is no path
|
|
mutable ssize_t _backup_revision;
|
|
|
|
std::string _virtual_path;
|
|
std::string _custom_name;
|
|
mutable size_t _untitled_count; // this is ≠ 0 if the document is untitled
|
|
|
|
struct grammar_callback_t : parse::grammar_t::callback_t
|
|
{
|
|
grammar_callback_t (document_t& doc) : _document(doc) { }
|
|
void grammar_did_change () { _document.grammar_did_change(); }
|
|
private:
|
|
document_t& _document;
|
|
};
|
|
|
|
parse::grammar_ptr _grammar;
|
|
grammar_callback_t _grammar_callback;
|
|
|
|
mutable std::string _file_type; // this may also be in the settings
|
|
mutable std::string _path_attributes;
|
|
// oak::uuid_t _grammar_uuid;
|
|
|
|
std::shared_ptr<ng::buffer_t> _buffer;
|
|
std::string _pristine_buffer = NULL_STR;
|
|
std::shared_ptr<ng::undo_manager_t> _undo_manager;
|
|
void mark_pristine ();
|
|
|
|
// std::string _folder; // when there is no path, this value is where the document will likely end up, i.e, used for retrieving settings and default save location
|
|
osx::authorization_t _authorization; // when opened via sudo
|
|
|
|
friend struct document_tracker_t;
|
|
size_t untitled_count () const { return _untitled_count; }
|
|
|
|
std::string _disk_encoding;
|
|
std::string _disk_newlines;
|
|
bool _disk_bom;
|
|
|
|
protected: // so that we can trigger the callback in unit tests
|
|
watch_ptr _file_watcher;
|
|
friend struct watch_t;
|
|
void watch_callback (int flags, std::string const& newPath, bool async = true);
|
|
};
|
|
|
|
PUBLIC document_ptr create (std::string const& path = NULL_STR);
|
|
PUBLIC document_ptr find (oak::uuid_t const& uuid, bool searchBackups = true);
|
|
PUBLIC document_ptr from_content (std::string const& content, std::string const& fileType = NULL_STR);
|
|
PUBLIC bool is_binary (std::string const& path);
|
|
|
|
// ====================
|
|
// = Document scanner =
|
|
// ====================
|
|
|
|
struct PUBLIC scanner_t
|
|
{
|
|
WATCH_LEAKS(scanner_t);
|
|
|
|
scanner_t (std::string const& path, std::string const& glob = "*", std::string const& excludeGlob = "", bool follow_links = false, bool follow_hidden_folders = false, bool depth_first = false);
|
|
~scanner_t ();
|
|
|
|
bool is_running () const { return is_running_flag; }
|
|
void stop () { should_stop_flag = true; }
|
|
void wait () const { pthread_join(thread, NULL); }
|
|
|
|
static std::vector<document_ptr> open_documents ();
|
|
|
|
std::vector<document_ptr> accept_documents ();
|
|
std::string get_current_path () const;
|
|
|
|
private:
|
|
std::string path, glob, exclude_glob;
|
|
bool follow_links, follow_hidden_folders, depth_first;
|
|
|
|
pthread_t thread;
|
|
mutable pthread_mutex_t mutex;
|
|
volatile bool is_running_flag, should_stop_flag;
|
|
|
|
void thread_main ();
|
|
void scan_dir (std::string const& dir);
|
|
|
|
std::string current_path;
|
|
std::vector<document_ptr> documents;
|
|
std::set< std::pair<dev_t, ino_t> > seen_paths;
|
|
};
|
|
|
|
typedef std::shared_ptr<scanner_t> scanner_ptr;
|
|
|
|
} /* document */
|
|
|
|
#endif /* end of include guard: DOCUMENT_H_MIJOONQT */
|