Exemplo n.º 1
0
    bool getIndentForCurrentBlock (CodeDocument::Position pos, const String& tab,
                                   String& blockIndent, String& lastLineIndent)
    {
        int braceCount = 0;
        bool indentFound = false;

        while (pos.getLineNumber() > 0)
        {
            pos = pos.movedByLines (-1);

            const String line (pos.getLineText());
            const String trimmedLine (line.trimStart());

            braceCount += getBraceCount (trimmedLine.getCharPointer());

            if (braceCount > 0)
            {
                blockIndent = getLeadingWhitespace (line);
                if (! indentFound)
                    lastLineIndent = blockIndent + tab;

                return true;
            }

            if ((! indentFound) && trimmedLine.isNotEmpty())
            {
                indentFound = true;
                lastLineIndent = getLeadingWhitespace (line);
            }
        }

        return false;
    }
Exemplo n.º 2
0
const String CtrlrMidiBufferStatus::currentByte(const CodeDocument::Position &pos)
{
	const String current 	= owner.getCodeEditor().getTextInRange(Range<int>(pos.getPosition(), pos.getPosition()+1));
	const String next 		= owner.getCodeEditor().getTextInRange(Range<int>(pos.getPosition()+1, pos.getPosition()+2));
	const String previous 	= owner.getCodeEditor().getTextInRange(Range<int>(pos.getPosition()-1, pos.getPosition()));
	String byte;
	String ret;

	if (next.trim().isEmpty())
	{
        byte << previous << current;
	}

	if (previous.trim().isEmpty())
	{
		byte << current << next;
	}

	if (!byte.isEmpty())
	{
		return (hexString(byte));
	}

	return (String::empty);
}
const Rectangle CodeEditorComponent::getCharacterBounds (const CodeDocument::Position& pos) const throw()
{
    return Rectangle (roundToInt ((gutter - xOffset * charWidth) + indexToColumn (pos.getLineNumber(), pos.getIndexInLine()) * charWidth),
                      (pos.getLineNumber() - firstLineOnScreen) * lineHeight,
                      roundToInt (charWidth),
                      lineHeight);
}
Exemplo n.º 4
0
void CtrlrMidiBufferStatus::update(const int x, const int y)
{
	size.setText(STR(owner.getDataSize()/3));

	status.setFont (statusFont);
	status.setText ("Byte: ");
	CodeDocument::Position pos = owner.getCodeEditor().getPositionAt (x,y);

	status.append (STR(pos.getPosition()/3), statusFont.boldened());
	status.append ("/"+STR(pos.getPosition()), statusFont);
	status.append (" "+currentByte(pos), statusFont);

	Range<int> sel = owner.getCodeEditor().getHighlightedRegion();
	if (!sel.isEmpty())
	{
		const int end   = sel.getEnd() / 3;
		const int start = sel.getStart() / 3;
		String selection = owner.getCodeEditor().getTextInRange (Range<int> (sel.getStart(),sel.getEnd())).trim();

		status.append (" Selected("+STR((end - start)+1)+"): ", statusFont);
		status.append (STR(start), statusFont.boldened());
		status.append (" - ", statusFont);
		status.append (STR(end), statusFont.boldened());
		status.append (" "+hexString(selection), statusFont);
	}

	repaint();
}
Exemplo n.º 5
0
void LivePropertyEditorBase::findOriginalValueInCode()
{
    CodeDocument::Position pos (document, value.sourceLine, 0);
    String line (pos.getLineText());
    String::CharPointerType p (line.getCharPointer());

    p = CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT"));

    if (p.isEmpty())
    {
        // Not sure how this would happen - some kind of mix-up between source code and line numbers..
        jassertfalse;
        return;
    }

    p += (int) (sizeof ("JUCE_LIVE_CONSTANT") - 1);
    p = p.findEndOfWhitespace();

    if (! CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT")).isEmpty())
    {
        // Aargh! You've added two JUCE_LIVE_CONSTANT macros on the same line!
        // They're identified by their line number, so you must make sure each
        // one goes on a separate line!
        jassertfalse;
    }

    if (p.getAndAdvance() == '(')
    {
        String::CharPointerType start (p), end (p);

        int depth = 1;

        while (! end.isEmpty())
        {
            const juce_wchar c = end.getAndAdvance();

            if (c == '(')  ++depth;
            if (c == ')')  --depth;

            if (depth == 0)
            {
                --end;
                break;
            }
        }

        if (end > start)
        {
            valueStart = CodeDocument::Position (document, value.sourceLine, (int) (start - line.getCharPointer()));
            valueEnd   = CodeDocument::Position (document, value.sourceLine, (int) (end   - line.getCharPointer()));

            valueStart.setPositionMaintained (true);
            valueEnd.setPositionMaintained (true);

            wasHex = String (start, end).containsIgnoreCase ("0x");
        }
    }
}
void CtrlrLuaMethodCodeEditor::mouseDown (const MouseEvent &e)
{
	CodeDocument::Position pos = editorComponent->getCaretPos();
	String url;
	if (isMouseOverUrl (pos, &url))
	{
		URL(url).launchInDefaultBrowser();
	}
	owner.setPositionLabelText ("Line:  " + String(pos.getLineNumber()+1) + " Column: " + String(pos.getIndexInLine()));
}
void GenericCodeEditorComponent::findNext (bool forwards, bool skipCurrentSelection)
{
	const Range<int> highlight (getHighlightedRegion());
	const CodeDocument::Position startPos (getDocument(), skipCurrentSelection ? highlight.getEnd()
		: highlight.getStart());
	int lineNum = startPos.getLineNumber();
	int linePos = startPos.getIndexInLine();

	const int totalLines = getDocument().getNumLines();
	const String searchText (getSearchString());
	const bool caseSensitive = isCaseSensitiveSearch();

	for (int linesToSearch = totalLines; --linesToSearch >= 0;)
	{
		String line (getDocument().getLine (lineNum));
		int index;

		if (forwards)
		{
			index = caseSensitive ? line.indexOf (linePos, searchText)
				: line.indexOfIgnoreCase (linePos, searchText);
		}
		else
		{
			if (linePos >= 0)
				line = line.substring (0, linePos);

			index = caseSensitive ? line.lastIndexOf (searchText)
				: line.lastIndexOfIgnoreCase (searchText);
		}

		if (index >= 0)
		{
			const CodeDocument::Position p (getDocument(), lineNum, index);
			selectRegion (p, p.movedBy (searchText.length()));
			break;
		}

		if (forwards)
		{
			linePos = 0;
			lineNum = (lineNum + 1) % totalLines;
		}
		else
		{
			if (--lineNum < 0)
				lineNum = totalLines - 1;

			linePos = -1;
		}
	}
}
void CodeEditorComponent::moveLineDelta (const int delta, const bool selecting)
{
    CodeDocument::Position pos (caretPos);
    const int newLineNum = pos.getLineNumber() + delta;

    if (columnToTryToMaintain < 0)
        columnToTryToMaintain = indexToColumn (pos.getLineNumber(), pos.getIndexInLine());

    pos.setLineAndIndex (newLineNum, columnToIndex (newLineNum, columnToTryToMaintain));

    const int colToMaintain = columnToTryToMaintain;
    moveCaretTo (pos, selecting);
    columnToTryToMaintain = colToMaintain;
}
    bool update (CodeDocument& codeDoc, int lineNum,
                 CodeDocument::Iterator& source,
                 CodeTokeniser* tokeniser, const int tabSpaces,
                 const CodeDocument::Position& selStart,
                 const CodeDocument::Position& selEnd)
    {
        Array <SyntaxToken> newTokens;
        newTokens.ensureStorageAllocated (8);

        if (tokeniser == nullptr)
        {
            const String line (codeDoc.getLine (lineNum));
            addToken (newTokens, line, line.length(), -1);
        }
        else if (lineNum < codeDoc.getNumLines())
        {
            const CodeDocument::Position pos (codeDoc, lineNum, 0);
            createTokens (pos.getPosition(), pos.getLineText(),
                          source, *tokeniser, newTokens);
        }

        replaceTabsWithSpaces (newTokens, tabSpaces);

        int newHighlightStart = 0;
        int newHighlightEnd = 0;

        if (selStart.getLineNumber() <= lineNum && selEnd.getLineNumber() >= lineNum)
        {
            const String line (codeDoc.getLine (lineNum));

            CodeDocument::Position lineStart (codeDoc, lineNum, 0), lineEnd (codeDoc, lineNum + 1, 0);
            newHighlightStart = indexToColumn (jmax (0, selStart.getPosition() - lineStart.getPosition()),
                                               line, tabSpaces);
            newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selEnd.getPosition() - lineStart.getPosition()),
                                             line, tabSpaces);
        }

        if (newHighlightStart != highlightColumnStart || newHighlightEnd != highlightColumnEnd)
        {
            highlightColumnStart = newHighlightStart;
            highlightColumnEnd = newHighlightEnd;
        }
        else if (tokens == newTokens)
        {
            return false;
        }

        tokens.swapWith (newTokens);
        return true;
    }
void CtrlrLuaMethodCodeEditor::reportFoundMatch (CodeDocument &document, const String &methodName, const Range<int> range)
{
	CodeDocument::Position pos (document, range.getStart());
	AttributedString as;
	as.append ("Method: ", Colours::black);
	as.append (methodName, Colours::blue);

	as.append ("\tline: ", Colours::black);
	as.append (String(pos.getLineNumber()+1), Colours::darkgreen);

	as.append ("\tstart: ", Colours::black);
	as.append (String(range.getStart()), Colours::darkgreen);

	as.append ("\tend: ", Colours::black);
	as.append (String(range.getEnd()), Colours::darkgreen);

	owner.getMethodEditArea()->insertOutput (as);
}
//==============================================================================
void CodeEditorComponent::codeDocumentChanged (const CodeDocument::Position& affectedTextStart,
                                               const CodeDocument::Position& affectedTextEnd)
{
    clearCachedIterators (affectedTextStart.getLineNumber());

    triggerAsyncUpdate();

    ((CaretComponent*) caret)->updatePosition (*this);

    if (affectedTextEnd.getPosition() >= selectionStart.getPosition()
         && affectedTextStart.getPosition() <= selectionEnd.getPosition())
        deselectAll();

    if (caretPos.getPosition() > affectedTextEnd.getPosition()
         || caretPos.getPosition() < affectedTextStart.getPosition())
        moveCaretTo (affectedTextStart, false);

    updateScrollBars();
}
Exemplo n.º 12
0
void MLDebugDisplay::display()
{
	const ScopedLock lock(mStreamLock);	

	// if any text is selected let debug output accumulate in stream. 
	int selectSize = mpComp->getHighlightedRegion().getLength();
	if(selectSize > 0) return;
	
	mStream.flush();
	std::string outStr = mStream.str();
	const char* pOutput = outStr.c_str();
	String newStr(pOutput);

	// erase stream contents
	mStream.str(std::string());

	int len = newStr.length();
	if (len > 0)
	{
		// delete beginning if too big
		const CodeDocument::Position pos = mpComp->getCaretPos();
		const int tc = pos.getPosition();
		if (tc > kMLDebugMaxChars)
		{
			mpComp->loadContent("");
			debug() << "----debug data > " << (int)kMLDebugMaxChars << " bytes, truncated----\n\n";
		}
		
		int lastDocLine = mDoc.getNumLines();
		int startLine = mpComp->getFirstLineOnScreen();
		int endLine = startLine + mpComp->getNumLinesOnScreen();		
		mpComp->moveCaretToEnd(false);
		mpComp->insertTextAtCaret(newStr);
		
		// if end of doc is off screen, reset saved position (don't scroll to text)
		if(lastDocLine > endLine + 1)
		{
			mpComp->scrollToLine(startLine);
		}
	}
}
void CodeEditorComponent::indentSelectedLines (const int spacesToAdd)
{
    newTransaction();

    CodeDocument::Position oldSelectionStart (selectionStart), oldSelectionEnd (selectionEnd), oldCaret (caretPos);
    oldSelectionStart.setPositionMaintained (true);
    oldSelectionEnd.setPositionMaintained (true);
    oldCaret.setPositionMaintained (true);

    const int lineStart = selectionStart.getLineNumber();
    int lineEnd = selectionEnd.getLineNumber();

    if (lineEnd > lineStart && selectionEnd.getIndexInLine() == 0)
        --lineEnd;

    for (int line = lineStart; line <= lineEnd; ++line)
    {
        const String lineText (document.getLine (line));
        const int nonWhitespaceStart = CodeEditorHelpers::findFirstNonWhitespaceChar (lineText);

        if (nonWhitespaceStart > 0 || lineText.trimStart().isNotEmpty())
        {
            const CodeDocument::Position wsStart (document, line, 0);
            const CodeDocument::Position wsEnd   (document, line, nonWhitespaceStart);

            const int numLeadingSpaces = indexToColumn (line, wsEnd.getIndexInLine());
            const int newNumLeadingSpaces = jmax (0, numLeadingSpaces + spacesToAdd);

            if (newNumLeadingSpaces != numLeadingSpaces)
            {
                document.deleteSection (wsStart, wsEnd);
                document.insertText (wsStart, getTabString (newNumLeadingSpaces));
            }
        }
    }

    selectionStart = oldSelectionStart;
    selectionEnd = oldSelectionEnd;
    caretPos = oldCaret;
}
Exemplo n.º 14
0
void CodeEditor::codeDocumentChanged(const CodeDocument::Position& affectedTextStart, const CodeDocument::Position& affectedTextEnd)
{
	static const String BRACKETS[] = {String(L"("), String(L")"), String(L"{"), String(L"}"), String(L"["), String(L"]"), String(L"<"), String(L">"), String(L"'"), String(L"'"), String(L"\""), String(L"\"")};
	if(do_bracket_closing.getValue() && affectedTextEnd.getPosition() - affectedTextStart.getPosition() == 1){		//assume that the length of the affected text is 1
		//We're finding an opening character and inserting the other one. 
		const String C = String::charToString(affectedTextStart.getCharacter());
		int index = 0;
		for(; index < numElementsInArray(BRACKETS); index += 2){		//search for an existing parenthesis
			if(C == BRACKETS[index]){
				break;
			}
		}

		if(index < numElementsInArray(BRACKETS)){		//If the index is out of range, we couldn't find the first character
			editor->insertTextAtCaret(BRACKETS[index+1]);
			editor->moveCaretTo(affectedTextEnd, false);
		}
	}

	static const String LOOK_UP_CHARS[] = {String(L"{"), String(L"}")};

	if(do_auto_indent.getValue() && affectedTextStart.getLineNumber() < affectedTextEnd.getLineNumber()){		//assume that we're at the beginning of a line
		//calculate the number of tabs that will be inserted to the next line
		const String LINE_ABOVE = affectedTextStart.getLineText(), LINE = affectedTextEnd.getLineText();
		const int TAB_SIZE = editor->getTabSize();
		const int LENGTH_BEFORE = LINE_ABOVE.trimEnd().length();
		const int LENGTH_AFTER = LINE_ABOVE.trimStart().length();
		const String TARGET_STRINGS[] = {String::charToString(affectedTextStart.movedBy(-1).getCharacter()), String::charToString(affectedTextEnd.getCharacter())};
		int tab_size_to_add = (TARGET_STRINGS[0] == LOOK_UP_CHARS[0] && TARGET_STRINGS[1] != LOOK_UP_CHARS[1]) ? ((LENGTH_AFTER - LENGTH_BEFORE) / TAB_SIZE) + 1	//add another tab
							: (TARGET_STRINGS[1] == LOOK_UP_CHARS[1] && TARGET_STRINGS[0] != LOOK_UP_CHARS[0]) ? ((LENGTH_AFTER - LENGTH_BEFORE) / TAB_SIZE) - 1	//remove one tab
																											   : ((LENGTH_AFTER - LENGTH_BEFORE) / TAB_SIZE);

		for(; tab_size_to_add > 0; --tab_size_to_add){
			editor->insertTabAtCaret();
		}
	}
}
Exemplo n.º 15
0
const CodeDocument::Position CodeDocument::Position::movedBy (const int characterDelta) const
{
    CodeDocument::Position p (*this);
    p.moveBy (characterDelta);
    return p;
}
    bool update (CodeDocument& document, int lineNum,
                 CodeDocument::Iterator& source,
                 CodeTokeniser* analyser, const int spacesPerTab,
                 const CodeDocument::Position& selectionStart,
                 const CodeDocument::Position& selectionEnd)
    {
        OwnedArray <SyntaxToken> newTokens;

        if (analyser == 0)
        {
            newTokens.add (new SyntaxToken (document.getLine (lineNum), -1));
        }
        else if (lineNum < document.getNumLines())
        {
            const CodeDocument::Position pos (&document, lineNum, 0);
            createTokens (pos.getPosition(), pos.getLineText(),
                          source, analyser, newTokens);
        }

        replaceTabsWithSpaces (newTokens, spacesPerTab);

        int newHighlightStart = 0;
        int newHighlightEnd = 0;

        if (selectionStart.getLineNumber() <= lineNum && selectionEnd.getLineNumber() >= lineNum)
        {
            const String line (document.getLine (lineNum));

            CodeDocument::Position lineStart (&document, lineNum, 0), lineEnd (&document, lineNum + 1, 0);
            newHighlightStart = indexToColumn (jmax (0, selectionStart.getPosition() - lineStart.getPosition()),
                                               line, spacesPerTab);
            newHighlightEnd = indexToColumn (jmin (lineEnd.getPosition() - lineStart.getPosition(), selectionEnd.getPosition() - lineStart.getPosition()),
                                             line, spacesPerTab);
        }

        if (newHighlightStart != highlightColumnStart || newHighlightEnd != highlightColumnEnd)
        {
            highlightColumnStart = newHighlightStart;
            highlightColumnEnd = newHighlightEnd;
        }
        else
        {
            if (tokens.size() == newTokens.size())
            {
                bool allTheSame = true;

                for (int i = newTokens.size(); --i >= 0;)
                {
                    if (*tokens.getUnchecked(i) != *newTokens.getUnchecked(i))
                    {
                        allTheSame = false;
                        break;
                    }
                }

                if (allTheSame)
                    return false;
            }
        }

        tokens.swapWithArray (newTokens);
        return true;
    }
bool CtrlrLuaMethodCodeEditor::keyStateChanged (bool isKeyDown, Component *originatingComponent)
{
	CodeDocument::Position pos = editorComponent->getCaretPos();
	owner.setPositionLabelText ("Line:  " + String(pos.getLineNumber()+1) + " Column: " + String(pos.getIndexInLine()));
	return (false);
}
bool CtrlrLuaMethodCodeEditor::keyPressed (const KeyPress &key, Component *originatingComponent)
{
    if (key.getModifiers().isCommandDown() )
	{
		if(key.getKeyCode() == 9)
		{
			owner.keyPressed (key, originatingComponent);
			return (true);
		}
		if (key.getKeyCode() == 83) // CTRL + S
		{
			saveDocument();
			return (true);
		}
		if (CharacterFunctions::toUpperCase ((juce_wchar) (key.getKeyCode())) == 70) // CTRL + F
		{
			// Show search Dialog
			editorComponent->showFindPanel();
			return (true);
		}
		if (CharacterFunctions::toUpperCase ((juce_wchar) (key.getKeyCode())) == 71) // CTRL + G
		{
			// Show Go To Dialog
			editorComponent->showGoTOPanel();
			return (true);
		}
		if (CharacterFunctions::toUpperCase ((juce_wchar) (key.getKeyCode())) == 72) // CTRL + H
		{
			// Show search Dialog
			editorComponent->showFindPanel(true);
			return (true);
		}

		if (key.getKeyCode() == KeyPress::deleteKey) // CTRL + Delete
		{
			owner.keyPressed(key, originatingComponent);
			return (true);
		}

		// search selected previous in current
		if (key.getModifiers().isShiftDown()
			&& key.getKeyCode() == KeyPress::F3Key) // CTRL + SHIFT + F3
		{
			editorComponent->findSelection(false);
			return (true);
		}
	}

	// search selected next in current
	if (key.getModifiers().isShiftDown() && key.getKeyCode() == KeyPress::F3Key) // SHIFT + F3
	{
		editorComponent->findSelection(true);
		return (true);
	}

	if (key.getKeyCode() == KeyPress::F7Key)
	{
		saveAndCompileDocument();
		return (true);
	}

	if (key.getKeyCode() == KeyPress::F8Key)
	{
		owner.saveAndCompilAllMethods();
		return (true);
	}

	CodeDocument::Position pos = editorComponent->getCaretPos();
	owner.setPositionLabelText ("Line:  " + String(pos.getLineNumber()+1) + " Column: " + String(pos.getIndexInLine()));
	return (false);
}
void CodeEditorComponent::mouseDoubleClick (const MouseEvent& e)
{
    CodeDocument::Position tokenStart (getPositionAt (e.x, e.y));
    CodeDocument::Position tokenEnd (tokenStart);

    if (e.getNumberOfClicks() > 2)
    {
        tokenStart.setLineAndIndex (tokenStart.getLineNumber(), 0);
        tokenEnd.setLineAndIndex (tokenStart.getLineNumber() + 1, 0);
    }
    else
    {
        while (CharacterFunctions::isLetterOrDigit (tokenEnd.getCharacter()))
            tokenEnd.moveBy (1);

        tokenStart = tokenEnd;

        while (tokenStart.getIndexInLine() > 0
                && CharacterFunctions::isLetterOrDigit (tokenStart.movedBy (-1).getCharacter()))
            tokenStart.moveBy (-1);
    }

    moveCaretTo (tokenEnd, false);
    moveCaretTo (tokenStart, true);
}
Exemplo n.º 20
0
const CodeDocument::Position CodeDocument::Position::movedByLines (const int deltaLines) const
{
    CodeDocument::Position p (*this);
    p.setLineAndIndex (getLineNumber() + deltaLines, getIndexInLine());
    return p;
}
Exemplo n.º 21
0
void CodeDocument::remove (const int startPos, const int endPos, const bool undoable)
{
    if (endPos <= startPos)
        return;

    if (undoable)
    {
        undoManager.perform (new CodeDocumentDeleteAction (*this, startPos, endPos));
    }
    else
    {
        Position startPosition (this, startPos);
        Position endPosition (this, endPos);

        maximumLineLength = -1;
        const int firstAffectedLine = startPosition.getLineNumber();
        const int endLine = endPosition.getLineNumber();
        int lastAffectedLine = firstAffectedLine + 1;
        CodeDocumentLine* const firstLine = lines.getUnchecked (firstAffectedLine);

        if (firstAffectedLine == endLine)
        {
            firstLine->line = firstLine->line.substring (0, startPosition.getIndexInLine())
                            + firstLine->line.substring (endPosition.getIndexInLine());
            firstLine->updateLength();
        }
        else
        {
            lastAffectedLine = lines.size();

            CodeDocumentLine* const lastLine = lines.getUnchecked (endLine);
            jassert (lastLine != nullptr);

            firstLine->line = firstLine->line.substring (0, startPosition.getIndexInLine())
                                + lastLine->line.substring (endPosition.getIndexInLine());
            firstLine->updateLength();

            int numLinesToRemove = endLine - firstAffectedLine;
            lines.removeRange (firstAffectedLine + 1, numLinesToRemove);
        }

        int i;
        for (i = firstAffectedLine + 1; i < lines.size(); ++i)
        {
            CodeDocumentLine* const l = lines.getUnchecked (i);
            const CodeDocumentLine* const previousLine = lines.getUnchecked (i - 1);
            l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
        }

        checkLastLineStatus();

        const int totalChars = getNumCharacters();

        for (i = 0; i < positionsToMaintain.size(); ++i)
        {
            CodeDocument::Position* p = positionsToMaintain.getUnchecked(i);

            if (p->getPosition() > startPosition.getPosition())
                p->setPosition (jmax (startPos, p->getPosition() + startPos - endPos));

            if (p->getPosition() > totalChars)
                p->setPosition (totalChars);
        }

        sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);
    }
}
const bool CtrlrLuaMethodCodeEditor::isMouseOverUrl(CodeDocument::Position &position, String *url)
{
	if (position.getPosition() >= document.getNumCharacters())
	{
		return (false);
	}

	int moveLeft=0;

	while (!CharacterFunctions::isWhitespace(position.getCharacter()))
	{
		if (position.getPosition() <= 0)
			break;

		position.moveBy(-1);
		moveLeft++;
	}

	int start = position.getPosition();
	position.setPosition (position.getPosition()+moveLeft);

	while (!CharacterFunctions::isWhitespace(position.getCharacter()))
	{
		if (position.getPosition() >= document.getNumCharacters())
			break;

		position.moveBy(1);
	}

	int end = position.getPosition();

	const String word = document.getTextBetween (CodeDocument::Position(document, start), CodeDocument::Position(document, end)).trim();

	if (word.startsWith ("http://"))
	{
		if (url)
		{
			*url = word;
		}
		return (URL::isProbablyAWebsiteURL (word));
	}

	return (false);
}