Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -681,7 +681,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,22 @@
*/
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 org.fife.ui.rtextarea.readonly.ReadOnlyFileStructure;
import org.fife.ui.rtextarea.readonly.ReadOnlyFileStructureParser;

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;
import java.nio.file.Path;

/**
* An extension of {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}
Expand Down Expand Up @@ -456,18 +457,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 +477,73 @@ 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);
}

// 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 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;
}

// 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 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;
}

// No IOException thrown, so we can finally change the location.
charSet = ur.getEncoding();
String old = getFileFullPath();
this.loc = loc;
private RSyntaxDocument createLazyLoadDocument(FileLocation fileLocation, Charset charSet) throws IOException {
if( !fileLocation.isLocalAndExists() ){
throw new FileNotFoundException("ReadOnlyDocument supports only files from local file system");
}
Path filePath = Path.of(fileLocation.getFileFullPath());
ReadOnlyFileStructureParser fileStructureParser = new ReadOnlyFileStructureParser(filePath, charSet);
ReadOnlyFileStructure readOnlyFileStructure = fileStructureParser.readStructure();
ReadOnlyContent content = new ReadOnlyContent(filePath, charSet, readOnlyFileStructure);
return new ReadOnlyDocument(getTokenMarkerFactory(), getSyntaxEditingStyle(), content);
}

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 +733,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,14 @@
package org.fife.ui.rtextarea.readonly;

public class FileCharsCounter {

int count = 2;

public void onBufferRead(int readChars) {
count += readChars;
}

public int getCount() {
return count;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.fife.ui.rtextarea.readonly;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class FileOffsetLineDiscover {

int lastOffset = 0;

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

public List<Integer> getOffsets() {

List<Integer> lineOffsets = new ArrayList<>();
lineOffsets.add(0);

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;
}

public void onBufferRead(char[] charBuffer, int readChars) {
for( int i = 0; i < readChars; i++ ){
lastOffset++;
char character = charBuffer[i];
if( character == '\n' ){
lfOffsets.add(lastOffset);
} else if( character == '\r' ){
crOffsets.add(lastOffset);
}
}
}
}
Loading