Example #1
0
void KateAutoIndent::keepIndent ( int line )
{
  // no line in front, no work...
  if (line <= 0)
    return;

  // keep indentation: find line with content
  int nonEmptyLine = line - 1;
  while (nonEmptyLine >= 0) {
    if (doc->lineLength(nonEmptyLine) > 0) {
      break;
    }
    --nonEmptyLine;
  }
  Kate::TextLine prevTextLine = doc->plainKateTextLine(nonEmptyLine);
  Kate::TextLine textLine     = doc->plainKateTextLine(line);

  // textline not found, cu
  if (!prevTextLine || !textLine)
    return;

  const QString previousWhitespace = prevTextLine->leadingWhitespace();

  // remove leading whitespace, then insert the leading indentation
  doc->editStart ();

  if (!keepExtra)
  {
    const QString currentWhitespace = textLine->leadingWhitespace();
    doc->editRemoveText (line, 0, currentWhitespace.length());
  }

  doc->editInsertText (line, 0, previousWhitespace);
  doc->editEnd ();
}
Example #2
0
bool KateAutoIndent::doIndentRelative(int line, int change)
{
  kDebug (13060) << "doIndentRelative: line: " << line << " change: " << change;

  Kate::TextLine textline = doc->plainKateTextLine(line);

  // get indent width of current line
  int indentDepth = textline->indentDepth (tabWidth);
  int extraSpaces = indentDepth % indentWidth;

  // add change
  indentDepth += change;

  // if keepExtra is off, snap to a multiple of the indentWidth
  if (!keepExtra && extraSpaces > 0)
  {
    if (change < 0)
      indentDepth += indentWidth - extraSpaces;
    else
      indentDepth -= extraSpaces;
  }

  // do indent
  return doIndent(line, indentDepth);
}
Example #3
0
bool KateAutoIndent::doIndent(int line, int indentDepth, int align)
{
  kDebug (13060) << "doIndent: line: " << line << " indentDepth: " << indentDepth << " align: " << align;

  Kate::TextLine textline = doc->plainKateTextLine(line);

  // textline not found, cu
  if (!textline)
    return false;

  // sanity check
  if (indentDepth < 0)
    indentDepth = 0;

  const QString oldIndentation = textline->leadingWhitespace();

  // Preserve existing "tabs then spaces" alignment if and only if:
  //  - no alignment was passed to doIndent and
  //  - we aren't using spaces for indentation and
  //  - we aren't rounding indentation up to the next multiple of the indentation width and
  //  - we aren't using a combination to tabs and spaces for alignment, or in other words
  //    the indent width is a multiple of the tab width.
  bool preserveAlignment = !useSpaces && keepExtra && indentWidth % tabWidth == 0;
  if (align == 0 && preserveAlignment)
  {
    // Count the number of consecutive spaces at the end of the existing indentation
    int i = oldIndentation.size() - 1;
    while (i >= 0 && oldIndentation.at(i) == ' ')
      --i;
    // Use the passed indentDepth as the alignment, and set the indentDepth to
    // that value minus the number of spaces found (but don't let it get negative).
    align = indentDepth;
    indentDepth = qMax(0, align - (oldIndentation.size() - 1 - i));
  }

  QString indentString = tabString(indentDepth, align);

  // Modify the document *ONLY* if smth has really changed!
  if (oldIndentation != indentString)
  {
    // remove leading whitespace, then insert the leading indentation
    doc->editStart ();
    doc->editRemoveText (line, 0, oldIndentation.length());
    doc->editInsertText (line, 0, indentString);
    doc->editEnd ();
  }

  return true;
}
Example #4
0
QString KatePrefixStore::findPrefix(const Kate::TextLine& line, int start) const
{
  unsigned long long state = 0;
  for(int i = start; i < line->length(); ++i) {
    QChar c = line->at(i);
    const CharToOccurrenceStateHash& hash = m_transitionFunction[state];
    CharToOccurrenceStateHash::const_iterator it = hash.find(c.unicode());
    if(it == hash.end()) {
      return QString();
    }

    state = (*it).second;
    if(m_acceptingStates.contains(state)) {
      return line->string(start, i + 1 - start);
    }
  }
  return QString();
}
Example #5
0
bool TextBuffer::save (const QString &filename)
{
  // codec must be set!
  Q_ASSERT (m_textCodec);

  /**
   * construct correct filter device and try to open
   */
  QIODevice *file = KFilterDev::deviceForFile (filename, m_mimeTypeForFilterDev, false);
  if (!file->open (QIODevice::WriteOnly)) {
    delete file;
    return false;
  }

  /**
   * construct stream + disable Unicode headers
   */
  QTextStream stream (file);
  stream.setCodec (QTextCodec::codecForName("UTF-16"));

  // set the correct codec
  stream.setCodec (m_textCodec);

  // generate byte order mark?
  stream.setGenerateByteOrderMark (generateByteOrderMark());

  // our loved eol string ;)
  QString eol = "\n"; //m_doc->config()->eolString ();
  if (endOfLineMode() == eolDos)
    eol = QString ("\r\n");
  else if (endOfLineMode() == eolMac)
    eol = QString ("\r");

  // just dump the lines out ;)
  for (int i = 0; i < m_lines; ++i)
  {
    // get line to save
    Kate::TextLine textline = line (i);

    // strip trailing spaces
    if (m_removeTrailingSpaces)
    {
      int lastChar = textline->lastChar();
      if (lastChar > -1)
      {
        stream << textline->text().left (lastChar+1);
      }
    }
    else // simple, dump the line
      stream << textline->text();

    // append correct end of line string
    if ((i+1) < m_lines)
      stream << eol;
  }

  // flush stream
  stream.flush ();

  // close and delete file
  file->close ();
  delete file;

#ifndef Q_OS_WIN
  // ensure that the file is written to disk
  // we crete new qfile, as the above might be wrapper around compression
  QFile syncFile (filename);
  syncFile.open (QIODevice::ReadOnly);

#ifdef HAVE_FDATASYNC
  fdatasync (syncFile.handle());
#else
  fsync (syncFile.handle());
#endif
#endif

  // did save work?
  bool ok = stream.status() == QTextStream::Ok;

  // remember this revision as last saved if we had success!
  if (ok)
    m_history.setLastSavedRevision ();

  // report CODEC + ERRORS
  kDebug (13020) << "Saved file " << filename << "with codec" << m_textCodec->name()
    << (ok ? "without" : "with") << "errors";

  // emit signal on success
  if (ok)
    emit saved (filename);

  // return success or not
  return ok;
}
Example #6
0
QList<QTextLayout::FormatRange> KateRenderer::decorationsForLine( const Kate::TextLine& textLine, int line, bool selectionsOnly, KateRenderRange* completionHighlight, bool completionSelected ) const
{
  QList<QTextLayout::FormatRange> newHighlight;

  // Don't compute the highlighting if there isn't going to be any highlighting
  QList<Kate::TextRange *> rangesWithAttributes = m_doc->buffer().rangesForLine (line, m_printerFriendly ? 0 : m_view, true);
  if (selectionsOnly || textLine->attributesList().count() || rangesWithAttributes.count()) {
    RenderRangeList renderRanges;

    // Add the inbuilt highlighting to the list
    NormalRenderRange* inbuiltHighlight = new NormalRenderRange();
    const QVector<Kate::TextLineData::Attribute> &al = textLine->attributesList();
    for (int i = 0; i < al.count(); ++i)
      if (al[i].length > 0 && al[i].attributeValue > 0)
        inbuiltHighlight->addRange(new KTextEditor::Range(KTextEditor::Cursor(line, al[i].offset), al[i].length), specificAttribute(al[i].attributeValue));
    renderRanges.append(inbuiltHighlight);

    if (!completionHighlight) {
      // check for dynamic hl stuff
      const QSet<Kate::TextRange *> *rangesMouseIn = m_view ? m_view->rangesMouseIn () : 0;
      const QSet<Kate::TextRange *> *rangesCaretIn = m_view ? m_view->rangesCaretIn () : 0;
      bool anyDynamicHlsActive = m_view && (!rangesMouseIn->empty() || !rangesCaretIn->empty());

      // sort all ranges, we want that the most specific ranges win during rendering, multiple equal ranges are kind of random, still better than old smart rangs behavior ;)
      qSort (rangesWithAttributes.begin(), rangesWithAttributes.end(), rangeLessThanForRenderer);

      // loop over all ranges
      for (int i = 0; i < rangesWithAttributes.size(); ++i) {
        // real range
        Kate::TextRange *kateRange = rangesWithAttributes[i];

        // calculate attribute, default: normal attribute
        KTextEditor::Attribute::Ptr attribute = kateRange->attribute();
        if (anyDynamicHlsActive) {
          // check mouse in
          if (KTextEditor::Attribute::Ptr attributeMouseIn = attribute->dynamicAttribute (KTextEditor::Attribute::ActivateMouseIn)) {
            if (rangesMouseIn->contains (kateRange))
              attribute = attributeMouseIn;
          }

          // check caret in
          if (KTextEditor::Attribute::Ptr attributeCaretIn = attribute->dynamicAttribute (KTextEditor::Attribute::ActivateCaretIn)) {
            if (rangesCaretIn->contains (kateRange))
              attribute = attributeCaretIn;
          }
        }

        // span range
        NormalRenderRange *additionaHl = new NormalRenderRange();
        additionaHl->addRange(new KTextEditor::Range (*kateRange), attribute);
        renderRanges.append(additionaHl);
      }
    } else {
      // Add the code completion arbitrary highlight to the list
      renderRanges.append(completionHighlight);
    }

    // Add selection highlighting if we're creating the selection decorations
    if ((selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || m_view->blockSelection()) {
      NormalRenderRange* selectionHighlight = new NormalRenderRange();

      // Set up the selection background attribute TODO: move this elsewhere, eg. into the config?
      static KTextEditor::Attribute::Ptr backgroundAttribute;
      if (!backgroundAttribute)
        backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute());

      backgroundAttribute->setBackground(config()->selectionColor());
      backgroundAttribute->setForeground(attribute(KTextEditor::HighlightInterface::dsNormal)->selectedForeground().color());

      // Create a range for the current selection
      if (completionHighlight && completionSelected)
        selectionHighlight->addRange(new KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute);
      else
        if(m_view->blockSelection() && m_view->selectionRange().overlapsLine(line))
          selectionHighlight->addRange(new KTextEditor::Range(m_doc->rangeOnLine(m_view->selectionRange(), line)), backgroundAttribute);
        else {
          selectionHighlight->addRange(new KTextEditor::Range(m_view->selectionRange()), backgroundAttribute);
        }

      renderRanges.append(selectionHighlight);
    // highlighting for the vi visual modes
    }

    KTextEditor::Cursor currentPosition, endPosition;

    // Calculate the range which we need to iterate in order to get the highlighting for just this line
    if (selectionsOnly) {
      if(m_view->blockSelection()) {
        KTextEditor::Range subRange = m_doc->rangeOnLine(m_view->selectionRange(), line);
        currentPosition = subRange.start();
        endPosition = subRange.end();
      } else {
        KTextEditor::Range rangeNeeded = m_view->selectionRange() & KTextEditor::Range(line, 0, line + 1, 0);

        currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start());
        endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end());
      }
    } else {
      currentPosition = KTextEditor::Cursor(line, 0);
      endPosition = KTextEditor::Cursor(line + 1, 0);
    }

    // Main iterative loop.  This walks through each set of highlighting ranges, and stops each
    // time the highlighting changes.  It then creates the corresponding QTextLayout::FormatRanges.
    while (currentPosition < endPosition) {
      renderRanges.advanceTo(currentPosition);

      if (!renderRanges.hasAttribute()) {
        // No attribute, don't need to create a FormatRange for this text range
        currentPosition = renderRanges.nextBoundary();
        continue;
      }

      KTextEditor::Cursor nextPosition = renderRanges.nextBoundary();

      // Create the format range and populate with the correct start, length and format info
      QTextLayout::FormatRange fr;
      fr.start = currentPosition.column();

      if (nextPosition < endPosition || endPosition.line() <= line) {
        fr.length = nextPosition.column() - currentPosition.column();

      } else {
        // +1 to force background drawing at the end of the line when it's warranted
        fr.length = textLine->length() - currentPosition.column() + 1;
      }

      KTextEditor::Attribute::Ptr a = renderRanges.generateAttribute();
      if (a) {
        fr.format = *a;

        if(selectionsOnly) {
              assignSelectionBrushesFromAttribute(fr, *a);
        }
      }

      newHighlight.append(fr);

      currentPosition = nextPosition;
    }

    if (completionHighlight)
      // Don't delete external completion render range
      renderRanges.removeAll(completionHighlight);

    qDeleteAll(renderRanges);
  }

  return newHighlight;
}