lyx_mirror/development/lyx2lyx.lyx
Richard Heck de44d18b75 The beginnings of a "Programming lyx2lyx" manual, probably to be
extended to prefs2prefs, once that's working.



git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@36152 a592a061-630c-0410-9148-cb99ea01b6c8
2010-11-06 00:48:00 +00:00

1484 lines
25 KiB
Plaintext

#LyX 2.0.0svn created this file. For more info see http://www.lyx.org/
\lyxformat 404
\begin_document
\begin_header
\textclass article
\use_default_options true
\begin_modules
logicalmkup
\end_modules
\maintain_unincluded_children false
\language english
\inputencoding auto
\fontencoding global
\font_roman default
\font_sans default
\font_typewriter default
\font_default_family default
\use_xetex false
\font_sc false
\font_osf false
\font_sf_scale 100
\font_tt_scale 100
\graphics default
\default_output_format default
\output_sync 0
\bibtex_command default
\index_command default
\paperfontsize default
\spacing single
\use_hyperref false
\papersize default
\use_geometry false
\use_amsmath 1
\use_esint 1
\use_mhchem 1
\use_mathdots 1
\cite_engine basic
\use_bibtopic false
\use_indices false
\paperorientation portrait
\suppress_date false
\use_refstyle 1
\index Index
\shortcut idx
\color #008000
\end_index
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\paragraph_indentation default
\quotes_language english
\papercolumns 1
\papersides 1
\paperpagestyle default
\tracking_changes false
\output_changes false
\html_math_output 0
\html_be_strict false
\end_header
\begin_body
\begin_layout Title
Programming lyx2lyx
\end_layout
\begin_layout Author
Richard Heck
\end_layout
\begin_layout Standard
Contained herein are some observations and suggestions about how to write
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
routines, including some thoughts about common pitfalls.
\end_layout
\begin_layout Section*
The LyX_base Class
\end_layout
\begin_layout Standard
Conversion and reversion routines will always be defined as functions that
take an object of type
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
LyX_base
\end_layout
\end_inset
as argument.
This argument, conventionally called
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
document
\end_layout
\end_inset
, represents the LyX document being converted.
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
LyX_base
\end_layout
\end_inset
class is defined in the file
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
LyX.py
\end_layout
\end_inset
, and it has several properties and a number of methods.
\end_layout
\begin_layout Standard
Some of the most important properties are:
\end_layout
\begin_layout Description
backend Either
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
linuxdoc
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
docbook
\end_layout
\end_inset
, or
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
latex
\end_layout
\end_inset
, depending upon the document class
\end_layout
\begin_layout Description
textclass The layout file for this document, e.g.,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
article
\end_layout
\end_inset
.
\end_layout
\begin_layout Description
default_layout The default layout style for the class.
\begin_inset Newline newline
\end_inset
Note that this is all
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
knows about the layout.
It does not know what paragraph styles are available, for example, let
alone what their properties might be.
\end_layout
\begin_layout Description
encoding The document encoding.
\end_layout
\begin_layout Description
language The document language.
\end_layout
\begin_layout Standard
These three represent the content of the document.
\end_layout
\begin_layout Description
header The document header, meaning the lines that come before
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
begin_body
\end_layout
\end_inset
,
\emph on
except
\emph default
for the LaTeX preamble.
\end_layout
\begin_layout Description
preamble The LaTeX preamble.
\end_layout
\begin_layout Description
body The document body.
\end_layout
\begin_layout Standard
All three of these are lists of strings.
The importance of this point will be discussed later.
\end_layout
\begin_layout Standard
Important methods include:
\end_layout
\begin_layout Description
warning Writes its argument to the console as a warning.
(Also takes an optional argument, the debug level, which can be used to
suppress output below a certain debug level, but this is rarely used.)
\end_layout
\begin_layout Description
error Writes the warning and exits, unless we are in try_hard mode, which
is set with a command-line option.
Rarely used in converter code, but I shall mention times it might be used
below.
\end_layout
\begin_layout Description
set_parameter Sets the value of a header parameter.
This needs to be a parameter already present in the header or nothing will
happen.
\end_layout
\begin_layout Description
set_textclass This writes the value of the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
textclass
\end_layout
\end_inset
member variable to the header.
So, for example, one might have something like this in a reversion routine:
\end_layout
\begin_layout LyX-Code
if document.textclass = 'fancy_new_class':
\end_layout
\begin_layout LyX-Code
document.textclass = 'old_class'
\end_layout
\begin_layout LyX-Code
document.setclass()
\end_layout
\begin_layout Description
add_module Adds a LyX module to the list of modules to be loaded with the
document.
\end_layout
\begin_layout Description
get_module_list Returns the list of modules to be loaded.
\end_layout
\begin_layout Description
set_module_list Takes a list as argument and replaces the existing list
of modules.
\end_layout
\begin_layout Standard
There are some other methods, too, such as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
read()
\end_layout
\end_inset
, but those are more for `internal' use.
\end_layout
\begin_layout Standard
It is extremely important to understand that
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
is
\emph on
line-oriented
\emph default
.
That is,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
represents the content of a LyX file---the header, preamble, and body---as
lists of lines.
It is critical that one maintain this structure when modifying the document.
Since Python is not type-safe, one can easily fail to do so if one is not
careful, and this will cause problems.
\end_layout
\begin_layout Standard
For example, one must absolutely never do anything like this:
\end_layout
\begin_layout LyX-Code
newstuff = '
\backslash
\backslash
begin_inset ERT
\backslash
n, status collapsed
\backslash
n
\backslash
\end_layout
\begin_layout LyX-Code
\backslash
\backslash
begin_layout Plain Layout
\backslash
n
\backslash
nI am in ERT
\backslash
n
\backslash
\end_layout
\begin_layout LyX-Code
\backslash
\backslash
end_layout
\backslash
n
\backslash
n
\backslash
\backslash
end_inset
\backslash
n
\backslash
n'
\end_layout
\begin_layout LyX-Code
document.body[i:i] = newstuff
\end_layout
\begin_layout Standard
This is supposed to insert an InsetERT at line i of the document, and in
a sense it will.
But it has the potential to confuse
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
very badly.
Suppose at some later point in the conversion we want to change
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
begin_layout Plain Layout
\end_layout
\end_inset
to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
begin_layout PlainLayout
\end_layout
\end_inset
.
(In fact, this is actually done.) Then we are going to have code that looks
like:
\end_layout
\begin_layout LyX-Code
i = find_token(document.body, '
\backslash
\backslash
begin_layout Plain Layout', i)
\end_layout
\begin_layout Standard
This will not find the occurence of
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
begin_layout Plain Layout
\end_layout
\end_inset
that we just inserted.
This is because
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find_token
\end_layout
\end_inset
looks for things at the beginning of lines, and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
begin_layout Plain Layout
\end_layout
\end_inset
is not at the beginning of the long string
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newstuff
\end_layout
\end_inset
.
It follows a newline, to be sure, but that is different.
So what one should do instead is:
\end_layout
\begin_layout LyX-Code
newstuff = ['
\backslash
\backslash
begin_inset ERT', 'status collapsed',
\end_layout
\begin_layout LyX-Code
'
\backslash
\backslash
begin_layout Plain Layout', '', 'I am in ERT',
\end_layout
\begin_layout LyX-Code
'
\backslash
\backslash
end_layout', '', '
\backslash
\backslash
end_inset', '']
\end_layout
\begin_layout LyX-Code
document.body[i:i] = newstuff
\end_layout
\begin_layout Standard
That inserts a bunch of lines.
\end_layout
\begin_layout Section*
Utility Functions
\end_layout
\begin_layout Standard
There are two Python modules that provide commonly used functions for parsing
the file and modifying it.
The parsing functions are in
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
parser_tools
\end_layout
\end_inset
and the modifying functions are in
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx_tools
\end_layout
\end_inset
.
Both of these files have extensive documentation at the beginning that
lists the functions that are available and explains what they do.
Those writing
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
code should familiarize themselves with these functions.
\end_layout
\begin_layout Section*
Common Code Structures and Pitfalls
\end_layout
\begin_layout Standard
Now, as said, reversion routines receive an argument of type
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
LyX_base
\end_layout
\end_inset
, and they almost always have one of two sorts of structure, depending upon
whether it is the header or the body that one is modifying.
\end_layout
\begin_layout Standard
If it is the body, then the routine usually has this sort of structure:
\end_layout
\begin_layout LyX-Code
def revert_something(document):
\end_layout
\begin_layout LyX-Code
i = 0
\end_layout
\begin_layout LyX-Code
while True:
\end_layout
\begin_layout LyX-Code
i = find_token(document.body, '
\backslash
begin_inset FunkyInset', i)
\end_layout
\begin_layout LyX-Code
if i == -1:
\end_layout
\begin_layout LyX-Code
break
\end_layout
\begin_layout LyX-Code
# do something ...
\end_layout
\begin_layout LyX-Code
i += 1 # or other appropriate reset
\end_layout
\begin_layout Standard
Now, in the course of doing something, one will often want to look for content
in the inset or layout, or whatever, that one has found.
Suppose, for example, that one is trying to remove the new option
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
from Funky insets.
Then one might think to use code like this:
\end_layout
\begin_layout LyX-Code
j = find_token(document.body, 'newoption', i)
\end_layout
\begin_layout LyX-Code
if j == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find newoption in Funky inset!')
\end_layout
\begin_layout LyX-Code
break
\end_layout
\begin_layout LyX-Code
del document.body[j]
\end_layout
\begin_layout Standard
This is terrible code, for several reasons.
\end_layout
\begin_layout Standard
First, it is wrong to break on the error here.
The LyX file is corrupted, yes.
But that does not necessarily mean that it is unusable---LyX is pretty
forgiving---and just because we have failed to find this one option does
not mean we should give up so soon.
We need at least to try to remove the option from other Funky insets.
So the right think to do here is instead:
\end_layout
\begin_layout LyX-Code
j = find_token(document.body, 'newoption', i)
\end_layout
\begin_layout LyX-Code
if j == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find newoption in Funky inset!')
\end_layout
\begin_layout LyX-Code
i += 1
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
del document.body[j]
\end_layout
\begin_layout Standard
The second problem is that we have no way of knowing that the line we find
here is actually a line containing an option for the Funky inset on line
i.
Suppose this one is missing its
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
.
There might be a later one that has a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
.
Then
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find_token
\end_layout
\end_inset
will find the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
for the later one.
If we're just removing it, that might not be so bad.
But if we were doing something more extensive, it could be.
So, at the very least, we need to find the end of this inset and make sure
the option comes before that:
\end_layout
\begin_layout LyX-Code
k = find_end_of_inset(document.body, i)
\end_layout
\begin_layout LyX-Code
if k == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find end of inset at line ' + str(i))
\end_layout
\begin_layout LyX-Code
i += 1
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
j = find_token(document.body, 'newoption', i, k)
\end_layout
\begin_layout LyX-Code
if j == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find newoption in Funky inset!')
\end_layout
\begin_layout LyX-Code
i = k
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
del document.body[j]
\end_layout
\begin_layout Standard
Note that we can reset
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
i
\end_layout
\end_inset
to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
k
\end_layout
\end_inset
here only if we know that no Funky inset can occur inside a Funky inset.
Otherwise, it should have been
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
i += 1
\end_layout
\end_inset
, again.
\end_layout
\begin_layout Standard
Although it is not often done, there are definitely cases where we should
use
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
document.error()
\end_layout
\end_inset
rather than
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
document.warning()
\end_layout
\end_inset
here.
In particular, suppose that we are actually planning to remove Funky insets
altogether, or to replace them with ERT.
Then, if the file is so corrupt that we cannot find the end of the inset,
we cannot do this work, so we know we cannot produce a LyX file an older
version will be able to load.
In that case, it seems right just to abort, and if the user wants to
\begin_inset Quotes eld
\end_inset
try hard
\begin_inset Quotes erd
\end_inset
, she can run
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
lyx2lyx
\end_layout
\end_inset
from the command line and pass the appropriate opttion.
\end_layout
\begin_layout Standard
The routine above may still fail to do the right thing, however.
Suppose again that
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
is missing, but due to a strange typo, one of the lines of text in the
inset happens to begin with
\begin_inset Quotes eld
\end_inset
newoption
\begin_inset Quotes erd
\end_inset
.
Then find_token will find that line and we will remove text from the document.
This will not generally happen with command insets, but it can easily happen
with text insets.
In that case, one has to make sure the option comes before the content
of the inset, and to do that, we must find the first layout in the inset,
thus:
\end_layout
\begin_layout LyX-Code
k = find_end_of_inset(document.body, i)
\end_layout
\begin_layout LyX-Code
if k == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find end of inset at line ' + str(i))
\end_layout
\begin_layout LyX-Code
i += 1
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
m = find_token(document.body, '
\backslash
\backslash
begin_layout', i, k)
\end_layout
\begin_layout LyX-Code
if m == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find layout for inset at line '
\backslash
\end_layout
\begin_layout LyX-Code
+ str(i) + '.
Hoping for the best.')
\end_layout
\begin_layout LyX-Code
m = k
\end_layout
\begin_layout LyX-Code
j = find_token(document.body, 'newoption', i, m)
\end_layout
\begin_layout LyX-Code
if j == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find newoption in Funky inset!')
\end_layout
\begin_layout LyX-Code
i = k
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
del document.body[j]
\end_layout
\begin_layout Standard
The last problem, though it would be unlikely in this case, is that we might
find not
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
but
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoptions
\end_layout
\end_inset
, because
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find_token
\end_layout
\end_inset
only looks to see if the beginning of the line matches.
Typically, then, what one really wants is
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find_token_exact
\end_layout
\end_inset
, which makes sure that we are finding a complete token.
\begin_inset Foot
status collapsed
\begin_layout Plain Layout
In the current implementation, this function also ignores other differences
in whitespace.
This needs to be fixed.
\end_layout
\end_inset
So what we really want, for the entire function, is:
\end_layout
\begin_layout LyX-Code
def revert_something(document):
\end_layout
\begin_layout LyX-Code
i = 0
\end_layout
\begin_layout LyX-Code
while True:
\end_layout
\begin_layout LyX-Code
i = find_token(document.body, '
\backslash
begin_inset FunkyInset', i)
\end_layout
\begin_layout LyX-Code
if i == -1:
\end_layout
\begin_layout LyX-Code
break
\end_layout
\begin_layout LyX-Code
k = find_end_of_inset(document.body, i)
\end_layout
\begin_layout LyX-Code
if k == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find end of inset at line ' + str(i))
\end_layout
\begin_layout LyX-Code
i += 1
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
m = find_token(document.body, '
\backslash
\backslash
begin_layout', i, k)
\end_layout
\begin_layout LyX-Code
if m == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find layout for inset at line '
\backslash
\end_layout
\begin_layout LyX-Code
+ str(i) + '.
Hoping for the best.')
\end_layout
\begin_layout LyX-Code
m = k
\end_layout
\begin_layout LyX-Code
j = find_token(document.body, 'newoption', i, m)
\end_layout
\begin_layout LyX-Code
if j == -1:
\end_layout
\begin_layout LyX-Code
document.warning('Unable to find newoption in Funky inset!')
\end_layout
\begin_layout LyX-Code
i = k
\end_layout
\begin_layout LyX-Code
continue
\end_layout
\begin_layout LyX-Code
del document.body[j]
\end_layout
\begin_layout LyX-Code
i += 1
\end_layout
\begin_layout Standard
This is much more complicated than what we had before, but it is much more
reliable.
(Probably, much of this logic should be wrapped in a function.)
\end_layout
\begin_layout Standard
Another common error is relying too much on assumptions about the structure
of a valid LyX file.
Here is an example.
Suppose we want to add a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
noindent
\end_layout
\end_inset
flag to the first paragraph of any Funky inset.
Then it is tempting to do something like this:
\end_layout
\begin_layout LyX-Code
def add_noindent(document):
\end_layout
\begin_layout LyX-Code
i = 0
\end_layout
\begin_layout LyX-Code
while True:
\end_layout
\begin_layout LyX-Code
i = find_token(document.body, '
\backslash
begin_inset FunkyInset', i)
\end_layout
\begin_layout LyX-Code
if i == -1:
\end_layout
\begin_layout LyX-Code
break
\end_layout
\begin_layout LyX-Code
document.body.insert(i+4, '
\backslash
\backslash
noindent')
\end_layout
\begin_layout Standard
Experienced programmers will know that this is bad.
Where does the magic number 4 come from? The answer is that it comes from
examining the LyX file.
One looks a typical file containing a Funky inset and sees:
\end_layout
\begin_layout LyX-Code
\backslash
begin_inset Funky
\end_layout
\begin_layout LyX-Code
status collapsed
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\backslash
begin_layout Standard
\end_layout
\begin_layout LyX-Code
here is some content
\end_layout
\begin_layout LyX-Code
\backslash
end_layout
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\backslash
end_inset
\end_layout
\begin_layout Standard
So
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
noindent
\end_layout
\end_inset
goes three lines after the inset.
\end_layout
\begin_layout Standard
Most of the time, perhaps, but there is no guarantee that this will be correct,
and the same goes for any assumption of this sort.
That is so even if one has carefully studied the LyX source code and made
very sure about the output routine.
In particular, the empty line before
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\backslash
begin_layout
\end_layout
\end_inset
could easily disappear, without any change to the semantics.
Or another one could appear.
There are several reasons for this.
\end_layout
\begin_layout Standard
First, looking at the source code of the current version of LyX tells you
nothing about how the file might have been created by some other version.
Maybe we get tired of blank lines.
\end_layout
\begin_layout Standard
Second, LyX files are not always produced by LyX.
Some of them are produced by external scripts (sed, perl, etc) that people
write to do search and replace operations that are not possible inside
LyX.
Such files may end up having slightly different structures.
\end_layout
\begin_layout Standard
Third, and most importantly, the file you are modifying has almost certainly
already been through several other conversion routines.
It is very, very difficult to make sure one gets all the blank lines in
the right places, and people rarely check for this: They check to make
sure the file opens correctly and that its output is right, but who cares
how many blank lines there are? Again, it is the semantics that matters,
not the fine details of file structure.
\end_layout
\begin_layout Standard
Or consider this possibility: Someone else wrote a routine to remove
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
, but, since they failed to read this document, their routine has all the
bugs we discussed before.
As a result,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
newoption
\end_layout
\end_inset
is still there in several of the Funky insets in the document, how that
it has gotten to your routine.
So what you actually have is:
\end_layout
\begin_layout LyX-Code
\backslash
begin_inset Funky
\end_layout
\begin_layout LyX-Code
status collapsed
\end_layout
\begin_layout LyX-Code
newoption false
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\backslash
begin_layout Standard
\end_layout
\begin_layout LyX-Code
here is some content
\end_layout
\begin_layout LyX-Code
\backslash
end_layout
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\backslash
end_inset
\end_layout
\begin_layout Standard
This is not a valid LyX document of the format on which you are operating.
But surely you do not really want to produce this:
\end_layout
\begin_layout LyX-Code
\backslash
begin_inset Funky
\end_layout
\begin_layout LyX-Code
status collapsed
\end_layout
\begin_layout LyX-Code
newoption false
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\backslash
noindent
\end_layout
\begin_layout LyX-Code
\backslash
begin_layout Standard
\end_layout
\begin_layout LyX-Code
here is some content
\end_layout
\begin_layout LyX-Code
\backslash
end_layout
\end_layout
\begin_layout LyX-Code
\end_layout
\begin_layout LyX-Code
\backslash
end_inset
\end_layout
\begin_layout Standard
Then you will have made matters worse, and also failed to unindent the paragraph.
\end_layout
\end_body
\end_document