Skip to content

Commit

Permalink
LazyLoadDocument
Browse files Browse the repository at this point in the history
  • Loading branch information
basix86 committed Nov 14, 2022
1 parent 7bb63d9 commit 5cc7802
Show file tree
Hide file tree
Showing 19 changed files with 1,113 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import org.fife.ui.rsyntaxtextarea.modes.AbstractMarkupTokenMaker;
import org.fife.ui.rtextarea.RDocument;
import org.fife.ui.rtextarea.RGapContent;
import org.fife.util.DynamicIntArray;


Expand Down Expand Up @@ -110,6 +111,11 @@ public RSyntaxDocument(String syntaxStyle) {
* @param syntaxStyle The syntax highlighting scheme to use.
*/
public RSyntaxDocument(TokenMakerFactory tmf, String syntaxStyle) {
this(tmf, syntaxStyle, new RGapContent());
}

public RSyntaxDocument(TokenMakerFactory tmf, String syntaxStyle, Content content) {
super(content);
putProperty(tabSizeAttribute, 5);
lastTokensOnLines = new DynamicIntArray(400);
lastTokensOnLines.add(Token.NULL); // Initial (empty) line.
Expand Down Expand Up @@ -531,6 +537,9 @@ private void setSharedSegment(int line) {

}

public TokenMakerFactory getTokenMakerFactory() {
return tokenMakerFactory;
}

/**
* Sets the syntax style being used for syntax highlighting in this
Expand Down Expand Up @@ -680,4 +689,7 @@ private void updateSyntaxHighlightingInformation() {
}


public boolean isEditable() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ public void copyAsStyledText() {
* @return The document.
*/
@Override
protected Document createDefaultModel() {
protected RSyntaxDocument createDefaultModel() {
return new RSyntaxDocument(SYNTAX_STYLE_NONE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,19 @@
*/
package org.fife.ui.rsyntaxtextarea;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import org.fife.io.UnicodeReader;
import org.fife.io.UnicodeWriter;
import org.fife.ui.rtextarea.RTextAreaEditorKit;
import org.fife.ui.rtextarea.readonly.ReadOnlyContent;
import org.fife.ui.rtextarea.readonly.ReadOnlyDocument;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

import org.fife.io.UnicodeReader;
import org.fife.io.UnicodeWriter;
import org.fife.ui.rtextarea.RTextAreaEditorKit;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;

/**
* An extension of {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}
Expand Down Expand Up @@ -456,18 +454,17 @@ public void load(FileLocation loc) throws IOException {
* @see #save()
* @see #saveAs(FileLocation)
*/
public void load(FileLocation loc, Charset defaultEnc) throws IOException {
load(loc, defaultEnc == null ? null : defaultEnc.name());
public void load(FileLocation loc, String defaultEnc) throws IOException {
load(loc, defaultEnc == null ? Charset.defaultCharset() : Charset.forName(defaultEnc));
}


/**
* Loads the specified file in this editor. This method fires a property
* change event of type {@link #FULL_PATH_PROPERTY}.
*
* @param loc The location of the file to load. This cannot be
* <code>null</code>.
* @param defaultEnc The encoding to use when loading/saving the file.
* @param defaultCharset The encoding to use when loading/saving the file.
* This encoding will only be used if the file is not Unicode.
* If this value is <code>null</code>, the system default encoding
* is used.
Expand All @@ -477,41 +474,69 @@ public void load(FileLocation loc, Charset defaultEnc) throws IOException {
* @see #save()
* @see #saveAs(FileLocation)
*/
public void load(FileLocation loc, String defaultEnc) throws IOException {
public void load(FileLocation loc, Charset defaultCharset) throws IOException {
Charset fileLocationCharset = getFileLocationCharset(loc, defaultCharset);
RSyntaxDocument doc = createEditableDocument(loc, fileLocationCharset);
loadDocument(loc, doc, defaultCharset);
}

// For new local files, just go with it.
if (loc.isLocal() && !loc.isLocalAndExists()) {
this.charSet = defaultEnc!=null ? defaultEnc : getDefaultEncoding();
this.loc = loc;
setText(null);
discardAllEdits();
setDirty(false);
return;
public void loadLocalFileInReadOnlyDocument(File file, Charset defaultCharset) throws IOException {
FileLocation fileLocation = FileLocation.create(file);
Charset fileLocationCharset = getFileLocationCharset(fileLocation, defaultCharset);
RSyntaxDocument doc = createLazyLoadDocument(fileLocation, fileLocationCharset);
loadDocument(fileLocation, doc, defaultCharset);
}

private Charset getFileLocationCharset(FileLocation fileLocation, Charset defaultCharset) throws IOException {
try( InputStream is = fileLocation.getInputStream() ){
UnicodeReader ur = new UnicodeReader(is, defaultCharset);
defaultCharset = Charset.forName(ur.getEncoding());
}
return defaultCharset;
}

// Old local files and remote files, load 'em up. UnicodeReader will
// check for BOMs and handle them correctly in all cases, then pass
// rest of stream down to InputStreamReader.
UnicodeReader ur = new UnicodeReader(loc.getInputStream(), defaultEnc);
private RSyntaxDocument createEditableDocument(FileLocation loc, Charset charset) throws IOException {
RSyntaxDocument doc = createDefaultModel();
// For new local files, just go with it.
if( !loc.isLocal() || loc.isLocalAndExists() ){
try( InputStreamReader r = new InputStreamReader(loc.getInputStream(), charset) ){
RTextAreaEditorKit kit = (RTextAreaEditorKit) getUI().getEditorKit(this);
try{
// NOTE: Resets the "line separator" property.
kit.read(r, doc, 0);
} catch( BadLocationException e ){
throw new IOException(e.getMessage());
}
}
}
return doc;
}

// Remove listener so dirty flag doesn't get set when loading a file.
Document doc = getDocument();
doc.removeDocumentListener(this);
try (BufferedReader r = new BufferedReader(ur)) {
read(r, null);
} finally {
doc.addDocumentListener(this);
private RSyntaxDocument createLazyLoadDocument(FileLocation fileLocation, Charset charSet) throws IOException {
if( !fileLocation.isLocalAndExists() ){
throw new FileNotFoundException("ReadOnlyDucument supports only files from local file system");
}
return new ReadOnlyDocument(getTokenMarkerFactory(), getSyntaxEditingStyle(), new ReadOnlyContent(new File(fileLocation.getFileFullPath()), charSet));
}

// No IOException thrown, so we can finally change the location.
charSet = ur.getEncoding();
String old = getFileFullPath();
this.loc = loc;
public void loadDocument(FileLocation fileLocation, RSyntaxDocument doc, Charset charSet) {
this.charSet = charSet.name();
String oldFileFullPath = getFileFullPath();
setDocument(doc);
this.loc = fileLocation;
setDirty(false);
setCaretPosition(0);
discardAllEdits();
firePropertyChange(FULL_PATH_PROPERTY, old, getFileFullPath());
firePropertyChange(FULL_PATH_PROPERTY, oldFileFullPath, getFileFullPath());
setReadOnly(isReadOnly() && doc.isEditable());
}

public TokenMakerFactory getTokenMarkerFactory() {
Document document = getDocument();
if( document instanceof RSyntaxDocument ){
return ((RSyntaxDocument) document).getTokenMakerFactory();
}
return null;
}


Expand Down Expand Up @@ -701,7 +726,7 @@ public void setLineSeparator(String separator) {
/**
* Sets the line separator sequence to use when this file is saved (e.g.
* "<code>\n</code>", "<code>\r\n</code>" or "<code>\r</code>").
*
* <p>
* Besides parameter checking, this method is preferred over
* <code>getDocument().putProperty()</code> because can set the editor's
* dirty flag when the line separator is changed.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.fife.ui.rtextarea;

import javax.swing.text.BadLocationException;

public interface RContent {
char charAt(int offset) throws BadLocationException;
}
31 changes: 5 additions & 26 deletions RSyntaxTextArea/src/main/java/org/fife/ui/rtextarea/RDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
package org.fife.ui.rtextarea;

import javax.swing.text.BadLocationException;
import javax.swing.text.GapContent;
import javax.swing.text.PlainDocument;


Expand All @@ -21,14 +20,16 @@
*/
public class RDocument extends PlainDocument {


/**
* Constructor.
*/
public RDocument() {
super(new RGapContent());
this(new RGapContent());
}

public RDocument(Content content) {
super(content);
}

/**
* Returns the character in the document at the specified offset.
Expand All @@ -38,28 +39,6 @@ public RDocument() {
* @throws BadLocationException If the offset is invalid.
*/
public char charAt(int offset) throws BadLocationException {
return ((RGapContent)getContent()).charAt(offset);
return ((RContent) getContent()).charAt(offset);
}


/**
* Document content that provides fast access to individual characters.
*/
private static class RGapContent extends GapContent {

public char charAt(int offset) throws BadLocationException {
if (offset<0 || offset>=length()) {
throw new BadLocationException("Invalid offset", offset);
}
int g0 = getGapStart();
char[] array = (char[]) getArray();
if (offset<g0) { // below gap
return array[offset];
}
return array[getGapEnd() + offset - g0]; // above gap
}

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.fife.ui.rtextarea;

import javax.swing.text.BadLocationException;
import javax.swing.text.GapContent;

/**
* Document content that provides fast access to individual characters.
*/
public class RGapContent extends GapContent implements RContent {

@Override
public char charAt(int offset) throws BadLocationException {
if( offset < 0 || offset >= length() ){
throw new BadLocationException("Invalid offset", offset);
}
int g0 = getGapStart();
char[] array = (char[]) getArray();
if( offset < g0 ){ // below gap
return array[offset];
}
return array[getGapEnd() + offset - g0]; // above gap
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.fife.ui.rtextarea.readonly;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

class FileOffsetLineDiscover {

private static final Logger LOGGER = Logger.getLogger(FileOffsetLineDiscover.class.getName());

private FileOffsetLineDiscover() {
}

public static List<Integer> getOffsets(Path filePath, Charset charset) {

List<Integer> lfOffsets = new ArrayList<>();
Set<Integer> crOffsets = new HashSet<>();

List<Integer> lineOffsets = new ArrayList<>();

lineOffsets.add(0);

readFile(filePath, charset, lfOffsets, crOffsets);

for( Integer newLineIndex : lfOffsets ){

//reconize \n\r LFCR
if( crOffsets.contains(newLineIndex + 1) ){
int lfcrIndex = newLineIndex + 1;
lineOffsets.add(lfcrIndex);
crOffsets.remove(lfcrIndex);
}

//recognize \r\n CRLF
else if( crOffsets.contains(newLineIndex - 1) ){
int crlfOffset = newLineIndex - 1;
lineOffsets.add(newLineIndex);
crOffsets.remove(crlfOffset);
}

//add LF
else lineOffsets.add(newLineIndex);
}

lineOffsets.addAll(crOffsets);
lineOffsets.sort(Integer::compare);
return lineOffsets;
}


private static void readFile(Path filePath, Charset fixedSizeCharset, Collection<Integer> newLines, Collection<Integer> carrigeRetrun) {
try( BufferedReader bufferedReader = Files.newBufferedReader(filePath, fixedSizeCharset); ){
int offset = 0;
char character;
int readValue;
while( true ){
readValue = bufferedReader.read();
if( readValue == -1 ) return;
offset++;
character = (char) readValue;
if( character == '\n' ){
newLines.add(offset);
} else if( character == '\r' ){
carrigeRetrun.add(offset);
}


}
} catch( IOException e ){
LOGGER.log(Level.WARNING, "Unable to read line offsets from file", e);
}
}
}
Loading

0 comments on commit 5cc7802

Please sign in to comment.