]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
The logic of the endParagraph() routine is wrong. We should first
[lyx.git] / src / Buffer.cpp
index 5ef9f1e771804719887942c1d7b09118e5a4cf8c..aebe0c96cbe72760fbe127c206d236ddbeb1ce29 100644 (file)
@@ -309,11 +309,27 @@ public:
        CloneList * clone_list_;
        /// are we in the process of exporting this buffer?
        mutable bool doing_export;
+       /// compute statistics
+       /// \p from initial position
+       /// \p to points to the end position
+       void updateStatistics(DocIterator & from, DocIterator & to,
+                                                 bool skipNoOutput = true);
+       /// statistics accessor functions
+       int wordCount() const { return word_count_; }
+       int charCount(bool with_blanks) const {
+               return char_count_
+               + (with_blanks ? blank_count_ : 0);
+       }
 
 private:
        /// So we can force access via the accessors.
        mutable Buffer const * parent_buffer;
 
+       int word_count_;
+       int char_count_;
+       int blank_count_;
+
 };
 
 
@@ -525,6 +541,7 @@ Buffer * Buffer::cloneBufferOnly() const {
        CloneList * clones = cloned_buffers.back();
        Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this);
        clones->insert(buffer_clone);
+       buffer_clone->d->clone_list_ = clones;
        // we won't be cloning the children
        buffer_clone->d->children_positions.clear();
        return buffer_clone;
@@ -772,6 +789,7 @@ int Buffer::readHeader(Lexer & lex)
        params().html_latex_end.clear();
        params().html_math_img_scale = 1.0;
        params().output_sync_macro.erase();
+       params().local_layout.clear();
 
        for (int i = 0; i < 4; ++i) {
                params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
@@ -985,7 +1003,7 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn)
 
        d->file_fully_loaded = true;
        d->read_only = !d->filename.isWritable();
-       params().compressed = d->filename.isZippedFile();
+       params().compressed = formats.isZippedFile(d->filename);
        saveCheckSum();
        return ReadSuccess;
 }
@@ -1491,9 +1509,8 @@ void Buffer::writeLaTeXSource(otexstream & os,
                        Encoding const * const enc = runparams.encoding;
                        if (enc) {
                                for (size_t n = 0; n < inputpath.size(); ++n) {
-                                       docstring const glyph =
-                                               docstring(1, inputpath[n]);
-                                       if (enc->latexChar(inputpath[n], true) != glyph) {
+                                       if (!enc->encodable(inputpath[n])) {
+                                               docstring const glyph(1, inputpath[n]);
                                                LYXERR0("Uncodable character '"
                                                        << glyph
                                                        << "' in input path!");
@@ -1771,32 +1788,65 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
                         html::htmlize(doctitle, XHTMLStream::ESCAPE_ALL))
                   << "</title>\n";
 
-               os << "\n<!-- Text Class Preamble -->\n"
-                  << features.getTClassHTMLPreamble()
-                  << "\n<!-- Preamble Snippets -->\n"
-                  << from_utf8(features.getPreambleSnippets());
-
-               os << "\n<!-- Layout-provided Styles -->\n";
-               docstring const styleinfo = features.getTClassHTMLStyles();
-               if (!styleinfo.empty()) {
-                       os << "<style type='text/css'>\n"
-                               << styleinfo
-                               << "</style>\n";
-               }
+               docstring styles = features.getTClassHTMLPreamble();
+               if (!styles.empty())
+                       os << "\n<!-- Text Class Preamble -->\n" << styles << '\n';
+
+               styles = from_utf8(features.getPreambleSnippets());
+               if (!styles.empty())
+                       os << "\n<!-- Preamble Snippets -->\n" << styles << '\n';
+
+               // we will collect CSS information in a stream, and then output it
+               // either here, as part of the header, or else in a separate file.
+               odocstringstream css;
+               styles = from_utf8(features.getCSSSnippets());
+               if (!styles.empty())
+                       css << "/* LyX Provided Styles */\n" << styles << '\n';
+
+               styles = features.getTClassHTMLStyles();
+               if (!styles.empty())
+                       css << "/* Layout-provided Styles */\n" << styles << '\n';
 
                bool const needfg = params().fontcolor != RGBColor(0, 0, 0);
                bool const needbg = params().backgroundcolor != RGBColor(0xFF, 0xFF, 0xFF);
                if (needfg || needbg) {
-                               os << "<style type='text/css'>\nbody {\n";
+                               css << "\nbody {\n";
                                if (needfg)
-                                  os << "  color: "
+                                  css << "  color: "
                                            << from_ascii(X11hexname(params().fontcolor))
                                            << ";\n";
                                if (needbg)
-                                  os << "  background-color: "
+                                  css << "  background-color: "
                                            << from_ascii(X11hexname(params().backgroundcolor))
                                            << ";\n";
-                               os << "}\n</style>\n";
+                               css << "}\n";
+               }
+               
+               docstring const dstyles = css.str();
+               if (!dstyles.empty()) {
+                       bool written = false;
+                       if (params().html_css_as_file) {
+                               // open a file for CSS info
+                               ofdocstream ocss;
+                               string const fcssname = addName(temppath(), "docstyle.css");
+                               FileName const fcssfile = FileName(fcssname);
+                               if (openFileWrite(ocss, fcssfile)) {
+                                       ocss << dstyles;
+                                       ocss.close();
+                                       written = true;
+                                       // write link to header
+                                       os << "<link rel='stylesheet' href='docstyle.css' type='text/css' />\n";
+                                       // register file
+                                       runparams.exportdata->addExternalFile("xhtml", fcssfile);
+                               }
+                       }
+                       // we are here if the CSS is supposed to be written to the header
+                       // or if we failed to write it to an external file.
+                       if (!written) {
+                               os << "<style type='text/css'>\n"
+                                        << dstyles
+                                        << "\n</style>\n";
+                       }
                }
                os << "</head>\n";
        }
@@ -3257,7 +3307,14 @@ void Buffer::getSourceCode(odocstream & os, string const format,
                        docbookParagraphs(text(), *this, os, runparams);
                else if (runparams.flavor == OutputParams::HTML) {
                        XHTMLStream xs(os);
+                       setMathFlavor(runparams);
                        xhtmlParagraphs(text(), *this, xs, runparams);
+               } else if (runparams.flavor == OutputParams::TEXT) {
+                       bool dummy;
+                       // FIXME Handles only one paragraph, unlike the others.
+                       // Probably should have some routine with a signature like them.
+                       writePlaintextParagraph(*this,
+                               text().paragraphs()[par_begin], os, runparams, dummy);
                } else {
                        // latex or literate
                        otexstream ots(os, texrow);
@@ -3575,6 +3632,25 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
 }
 
 
+void Buffer::setMathFlavor(OutputParams & op) const
+{
+       switch (params().html_math_output) {
+       case BufferParams::MathML:
+               op.math_flavor = OutputParams::MathAsMathML;
+               break;
+       case BufferParams::HTML:
+               op.math_flavor = OutputParams::MathAsHTML;
+               break;
+       case BufferParams::Images:
+               op.math_flavor = OutputParams::MathAsImages;
+               break;
+       case BufferParams::LaTeX:
+               op.math_flavor = OutputParams::MathAsLaTeX;
+               break;
+       }
+}
+
+
 Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir,
        bool includeall, string & result_file) const
 {
@@ -3649,20 +3725,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
        // HTML backend
        else if (backend_format == "xhtml") {
                runparams.flavor = OutputParams::HTML;
-               switch (params().html_math_output) {
-               case BufferParams::MathML:
-                       runparams.math_flavor = OutputParams::MathAsMathML;
-                       break;
-               case BufferParams::HTML:
-                       runparams.math_flavor = OutputParams::MathAsHTML;
-                       break;
-               case BufferParams::Images:
-                       runparams.math_flavor = OutputParams::MathAsImages;
-                       break;
-               case BufferParams::LaTeX:
-                       runparams.math_flavor = OutputParams::MathAsLaTeX;
-                       break;
-               }
+               setMathFlavor(runparams);
                makeLyXHTMLFile(FileName(filename), runparams);
        } else if (backend_format == "lyx")
                writeFile(FileName(filename));
@@ -3674,13 +3737,11 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
        // LaTeX backend
        else if (backend_format == format) {
                runparams.nice = true;
-               if (!makeLaTeXFile(FileName(filename), string(), runparams)) {
-                       if (d->cloned_buffer_) {
-                               d->cloned_buffer_->d->errorLists["Export"] =
-                                       d->errorLists["Export"];
-                       }
+               bool const success = makeLaTeXFile(FileName(filename), string(), runparams);
+               if (d->cloned_buffer_)
+                       d->cloned_buffer_->d->errorLists["Export"] = d->errorLists["Export"];
+               if (!success)
                        return ExportError;
-               }
        } else if (!lyxrc.tex_allows_spaces
                   && contains(filePath(), ' ')) {
                Alert::error(_("File name error"),
@@ -3688,13 +3749,11 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
                return ExportTexPathHasSpaces;
        } else {
                runparams.nice = false;
-               if (!makeLaTeXFile(FileName(filename), filePath(), runparams)) {
-                       if (d->cloned_buffer_) {
-                               d->cloned_buffer_->d->errorLists["Export"] =
-                                       d->errorLists["Export"];
-                       }
+               bool const success = makeLaTeXFile(FileName(filename), string(), runparams);
+               if (d->cloned_buffer_)
+                       d->cloned_buffer_->d->errorLists["Export"] = d->errorLists["Export"];
+               if (!success)
                        return ExportError;
-               }
        }
 
        string const error_type = (format == "program")
@@ -4386,6 +4445,77 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
 }
 
 
+void Buffer::Impl::updateStatistics(DocIterator & from, DocIterator & to, bool skipNoOutput)
+{
+       bool inword = false;
+       word_count_ = 0;
+       char_count_ = 0;
+       blank_count_ = 0;
+       for (DocIterator dit = from ; dit != to && !dit.atEnd(); ) {
+               if (!dit.inTexted()) {
+                       dit.forwardPos();
+                       continue;
+               }
+               
+               Paragraph const & par = dit.paragraph();
+               pos_type const pos = dit.pos();
+               
+               // Copied and adapted from isWordSeparator() in Paragraph
+               if (pos == dit.lastpos()) {
+                       inword = false;
+               } else {
+                       Inset const * ins = par.getInset(pos);
+                       if (ins && skipNoOutput && !ins->producesOutput()) {
+                               // skip this inset
+                               ++dit.top().pos();
+                               // stop if end of range was skipped
+                               if (!to.atEnd() && dit >= to)
+                                       break;
+                               continue;
+                       } else if (!par.isDeleted(pos)) {
+                               if (par.isWordSeparator(pos)) 
+                                       inword = false;
+                               else if (!inword) {
+                                       ++word_count_;
+                                       inword = true;
+                               }
+                               if (ins && ins->isLetter())
+                                       ++char_count_;
+                               else if (ins && ins->isSpace())
+                                       ++blank_count_;
+                               else {
+                                       char_type const c = par.getChar(pos);
+                                       if (isPrintableNonspace(c))
+                                               ++char_count_;
+                                       else if (isSpace(c))
+                                               ++blank_count_;
+                               }
+                       }
+               }
+               dit.forwardPos();
+       }
+}
+
+
+void Buffer::updateStatistics(DocIterator & from, DocIterator & to, bool skipNoOutput) const
+{
+       d->updateStatistics(from, to, skipNoOutput);
+}
+
+
+int Buffer::wordCount() const
+{
+       return d->wordCount();
+}
+
+
+int Buffer::charCount(bool with_blanks) const
+{
+       return d->charCount(with_blanks);
+}
+
+
 Buffer::ReadStatus Buffer::reload()
 {
        setBusy(true);
@@ -4395,6 +4525,8 @@ Buffer::ReadStatus Buffer::reload()
        d->filename.refresh();
        docstring const disp_fn = makeDisplayPath(d->filename.absFileName());
 
+       // clear parent. this will get reset if need be.
+       d->setParent(0);
        ReadStatus const status = loadLyXFile();
        if (status == ReadSuccess) {
                updateBuffer();