mirror of https://github.com/buggins/dlangui.git
support writing of editor contents to file
This commit is contained in:
parent
00e4d207d4
commit
ec0f7ea8f4
|
@ -208,6 +208,7 @@ class OutputLineStream {
|
|||
}
|
||||
/// close stream
|
||||
void close() {
|
||||
flush();
|
||||
_stream.close();
|
||||
_buf = null;
|
||||
}
|
||||
|
@ -243,6 +244,10 @@ class LineStream {
|
|||
private uint _textLen; // position of last filled char in text buffer + 1
|
||||
private dchar[] _textBuf; // text buffer
|
||||
private bool _eof; // end of file, no more lines
|
||||
protected bool _bomDetected;
|
||||
protected int _crCount;
|
||||
protected int _lfCount;
|
||||
protected int _crlfCount;
|
||||
|
||||
/// Returns file name
|
||||
@property string filename() { return _filename; }
|
||||
|
@ -250,6 +255,25 @@ class LineStream {
|
|||
@property uint line() { return _line; }
|
||||
/// Returns file encoding EncodingType
|
||||
@property EncodingType encoding() { return _encoding; }
|
||||
|
||||
@property TextFileFormat textFormat() {
|
||||
LineEnding le = LineEnding.CRLF;
|
||||
if (_crlfCount) {
|
||||
if (_crCount == _lfCount)
|
||||
le = LineEnding.CRLF;
|
||||
else
|
||||
le = LineEnding.MIXED;
|
||||
} else if (_crCount > _lfCount) {
|
||||
le = LineEnding.CR;
|
||||
} else if (_lfCount > _crCount) {
|
||||
le = LineEnding.CR;
|
||||
} else {
|
||||
le = LineEnding.MIXED;
|
||||
}
|
||||
return TextFileFormat(_encoding, le, _bomDetected);
|
||||
}
|
||||
|
||||
|
||||
/// Returns error code
|
||||
@property int errorCode() { return _errorCode; }
|
||||
/// Returns error message
|
||||
|
@ -397,15 +421,21 @@ class LineStream {
|
|||
charsLeft = _textLen - _textPos;
|
||||
}
|
||||
dchar ch2 = (p < charsLeft - 1) ? _textBuf[_textPos + p + 1] : 0;
|
||||
if (ch2 == 0x0A)
|
||||
if (ch2 == 0x0A) {
|
||||
eol = p + 2;
|
||||
else
|
||||
_lfCount++;
|
||||
_crCount++;
|
||||
_crlfCount++;
|
||||
} else {
|
||||
eol = p + 1;
|
||||
_lfCount++;
|
||||
}
|
||||
break;
|
||||
} else if (ch == 0x0A || ch == 0x2028 || ch == 0x2029) {
|
||||
// single char eoln
|
||||
lastchar = p;
|
||||
eol = p + 1;
|
||||
_crCount++;
|
||||
break;
|
||||
} else if (ch == 0 || ch == 0x001A) {
|
||||
// eof
|
||||
|
@ -450,25 +480,34 @@ class LineStream {
|
|||
}
|
||||
|
||||
/// Factory for InputStream parser
|
||||
public static LineStream create(InputStream stream, string filename) {
|
||||
public static LineStream create(InputStream stream, string filename, bool autodetectUTFIfNoBOM = true) {
|
||||
ubyte[] buf = new ubyte[BYTE_BUFFER_SIZE];
|
||||
buf[0] = buf[1] = buf[2] = buf[3] = 0;
|
||||
if (!stream.isOpen)
|
||||
return null;
|
||||
uint len = cast(uint)stream.read(buf);
|
||||
LineStream res = null;
|
||||
if (buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) {
|
||||
return new Utf8LineStream(stream, filename, buf, len);
|
||||
res = new Utf8LineStream(stream, filename, buf, len);
|
||||
} else if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0xFE && buf[3] == 0xFF) {
|
||||
return new Utf32beLineStream(stream, filename, buf, len);
|
||||
res = new Utf32beLineStream(stream, filename, buf, len);
|
||||
} else if (buf[0] == 0xFF && buf[1] == 0xFE && buf[2] == 0x00 && buf[3] == 0x00) {
|
||||
return new Utf32leLineStream(stream, filename, buf, len);
|
||||
res = new Utf32leLineStream(stream, filename, buf, len);
|
||||
} else if (buf[0] == 0xFE && buf[1] == 0xFF) {
|
||||
return new Utf16beLineStream(stream, filename, buf, len);
|
||||
res = new Utf16beLineStream(stream, filename, buf, len);
|
||||
} else if (buf[0] == 0xFF && buf[1] == 0xFE) {
|
||||
return new Utf16leLineStream(stream, filename, buf, len);
|
||||
} else {
|
||||
return new AsciiLineStream(stream, filename, buf, len);
|
||||
res = new Utf16leLineStream(stream, filename, buf, len);
|
||||
}
|
||||
if (res) {
|
||||
res._bomDetected = true;
|
||||
} else {
|
||||
if (autodetectUTFIfNoBOM) {
|
||||
res = new Utf8LineStream(stream, filename, buf, len);
|
||||
} else {
|
||||
res = new AsciiLineStream(stream, filename, buf, len);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected bool invalidCharFlag;
|
||||
|
|
|
@ -27,6 +27,7 @@ import dlangui.widgets.controls;
|
|||
import dlangui.widgets.scroll;
|
||||
import dlangui.core.signals;
|
||||
import dlangui.core.collections;
|
||||
import dlangui.core.linestream;
|
||||
import dlangui.platforms.common.platform;
|
||||
import dlangui.widgets.menu;
|
||||
import dlangui.widgets.popup;
|
||||
|
@ -256,7 +257,10 @@ enum EditAction {
|
|||
/// delete content in range
|
||||
//Delete,
|
||||
/// replace range content with new content
|
||||
Replace
|
||||
Replace,
|
||||
|
||||
/// replace whole content
|
||||
ReplaceContent,
|
||||
}
|
||||
|
||||
/// edit operation details for EditableContent
|
||||
|
@ -435,6 +439,14 @@ class EditableContent {
|
|||
}
|
||||
return cast(dstring)buf;
|
||||
}
|
||||
|
||||
/// call listener to say that whole content is replaced e.g. by loading from file
|
||||
void notifyContentReplaced() {
|
||||
TextRange rangeBefore;
|
||||
TextRange rangeAfter;
|
||||
handleContentChange(new EditOperation(EditAction.ReplaceContent), rangeBefore, rangeAfter, this);
|
||||
}
|
||||
|
||||
/// replace whole text with another content
|
||||
@property EditableContent text(dstring newContent) {
|
||||
clearUndo();
|
||||
|
@ -445,6 +457,7 @@ class EditableContent {
|
|||
_lines.length = 1;
|
||||
_lines[0] = replaceEolsWithSpaces(newContent);
|
||||
}
|
||||
notifyContentReplaced();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -817,10 +830,22 @@ class EditableContent {
|
|||
void clearUndo() {
|
||||
_undoBuffer.clear();
|
||||
}
|
||||
|
||||
protected string _filename;
|
||||
protected TextFileFormat _format;
|
||||
|
||||
/// file used to load editor content
|
||||
@property string filename() {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
|
||||
/// load content form input stream
|
||||
bool load(InputStream f, string fname = null) {
|
||||
import dlangui.core.linestream;
|
||||
clear();
|
||||
_filename = fname;
|
||||
_format = TextFileFormat.init;
|
||||
try {
|
||||
LineStream lines = LineStream.create(f, fname);
|
||||
for (;;) {
|
||||
|
@ -832,13 +857,17 @@ class EditableContent {
|
|||
if (lines.errorCode != 0) {
|
||||
clear();
|
||||
Log.e("Error ", lines.errorCode, " ", lines.errorMessage, " -- at line ", lines.errorLine, " position ", lines.errorPos);
|
||||
notifyContentReplaced();
|
||||
return false;
|
||||
}
|
||||
// EOF
|
||||
_format = lines.textFormat;
|
||||
notifyContentReplaced();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e("Exception while trying to read file ", fname, " ", e.toString);
|
||||
clear();
|
||||
notifyContentReplaced();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -855,6 +884,47 @@ class EditableContent {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
/// save to output stream in specified format
|
||||
bool save(OutputStream stream, string filename, TextFileFormat format) {
|
||||
if (!filename)
|
||||
filename = _filename;
|
||||
_format = format;
|
||||
import dlangui.core.linestream;
|
||||
try {
|
||||
OutputLineStream writer = new OutputLineStream(stream, filename, format);
|
||||
scope(exit) { writer.close(); }
|
||||
for (int i = 0; i < _lines.length; i++) {
|
||||
writer.writeLine(_lines[i]);
|
||||
}
|
||||
// EOF
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e("Exception while trying to write file ", filename, " ", e.toString);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// save to output stream in current format
|
||||
bool save(OutputStream stream, string filename) {
|
||||
return save(stream, filename, _format);
|
||||
}
|
||||
/// save to file in specified format
|
||||
bool save(string filename, TextFileFormat format) {
|
||||
if (!filename)
|
||||
filename = _filename;
|
||||
try {
|
||||
std.stream.File f = new std.stream.File(filename, FileMode.Out);
|
||||
scope(exit) { f.close(); }
|
||||
return save(f, filename, format);
|
||||
} catch (Exception e) {
|
||||
Log.e("Exception while trying to save file ", filename, " ", e.toString);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// save to file in current format
|
||||
bool save(string filename) {
|
||||
return save(filename, _format);
|
||||
}
|
||||
}
|
||||
|
||||
/// base for all editor widgets
|
||||
|
@ -1133,10 +1203,20 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
updateMaxLineWidth();
|
||||
measureVisibleText();
|
||||
if (source is this) {
|
||||
if (operation.action == EditAction.ReplaceContent) {
|
||||
// loaded from file
|
||||
_caretPos = rangeAfter.end;
|
||||
_selectionRange.start = _caretPos;
|
||||
_selectionRange.end = _caretPos;
|
||||
ensureCaretVisible();
|
||||
correctCaretPos();
|
||||
requestLayout();
|
||||
} else {
|
||||
_caretPos = rangeAfter.end;
|
||||
_selectionRange.start = _caretPos;
|
||||
_selectionRange.end = _caretPos;
|
||||
ensureCaretVisible();
|
||||
}
|
||||
} else {
|
||||
correctCaretPos();
|
||||
// TODO: do something better (e.g. take into account ranges when correcting)
|
||||
|
|
Loading…
Reference in New Issue