=== modified file 'keyCommandsDoc.py'
--- keyCommandsDoc.py	2010-11-14 22:31:46 +0000
+++ keyCommandsDoc.py	2013-02-06 12:14:41 +0000
@@ -101,6 +101,8 @@
 		self._settingsHeaderRow = None
 		#: The number of layouts for settings in a settings section.
 		self._settingsNumLayouts = 0
+		#: The current line number being processed, used to present location of syntax errors
+		self._lineno = 0
 
 	def make(self):
 		"""Generate the Key Commands document.
@@ -127,6 +129,7 @@
 
 	def _make(self):
 		for line in self._ug:
+			self._lineno += 1
 			line = line.rstrip()
 			m = self.RE_COMMAND.match(line)
 			if m:
@@ -145,17 +148,17 @@
 		# Handle header commands.
 		if cmd == "title":
 			if self._kcSect > self.KCSECT_HEADER:
-				raise KeyCommandsError("title command is not valid here")
+				raise KeyCommandsError("%d, title command is not valid here" % self._lineno)
 			# Write the title and two blank lines to complete the txt2tags header section.
 			self._kc.write(arg + LINE_END * 3)
 			self._kcSect = self.KCSECT_CONFIG
 			self._kc.write("%%!includeconf: ../global.t2tconf%s" % LINE_END)
 			return
 		elif self._kcSect == self.KCSECT_HEADER:
-			raise KeyCommandsError("title must be the first command")
+			raise KeyCommandsError("%d, title must be the first command" % self._lineno)
 		elif cmd == "includeconf":
 			if self._kcSect > self.KCSECT_CONFIG:
-				raise KeyCommandsError("includeconf command is not valid here")
+				raise KeyCommandsError("%d, includeconf command is not valid here" % self._lineno)
 			self._kc.write("%%!includeconf: %s%s" % (arg, LINE_END))
 			return
 		elif self._kcSect == self.KCSECT_CONFIG:
@@ -180,7 +183,7 @@
 			self._handleSetting()
 
 		else:
-			raise KeyCommandsError("Invalid command %s" % cmd)
+			raise KeyCommandsError("%d, Invalid command %s" % (self._lineno, cmd))
 
 	def _areHeadingsPending(self):
 		return self._kcLastHeadingLevel < len(self._headings) - 1
@@ -211,7 +214,7 @@
 
 	def _handleSetting(self):
 		if not self._settingsHeaderRow:
-			raise KeyCommandsError("setting command cannot be used before settingsSection command")
+			raise KeyCommandsError("%d, setting command cannot be used before settingsSection command" % self._lineno)
 
 		if self._areHeadingsPending():
 			# There are new headings to write.
@@ -223,9 +226,10 @@
 
 		# The next line should be a heading which is the name of the setting.
 		line = next(self._ug)
+		self._lineno += 1
 		m = self.t2tRe["title"].match(line)
 		if not m:
-			raise KeyCommandsError("setting command must be followed by heading")
+			raise KeyCommandsError("%d, setting command must be followed by heading" % self._lineno)
 		name = m.group("txt")
 
 		# The next few lines should be table rows for each layout.
@@ -233,11 +237,12 @@
 		keys = []
 		for layout in xrange(self._settingsNumLayouts):
 			line = next(self._ug).strip()
+			self._lineno += 1
 			if ":" in line:
 				keys.append(line.split(":", 1)[1].strip())
 				break
 			elif not self.t2tRe["table"].match(line):
-				raise KeyCommandsError("setting command: There must be one table row for each keyboard layout")
+				raise KeyCommandsError("%d, setting command: There must be one table row for each keyboard layout" % self._lineno)
 			# This is a table row.
 			# The key will be the second column.
 			# TODO: Error checking.
@@ -250,11 +255,13 @@
 
 		# There should now be a blank line.
 		line = next(self._ug).strip()
+		self._lineno += 1
 		if line:
-			raise KeyCommandsError("setting command: The keyboard shortcuts must be followed by a blank line. Multiple keys must be included in a table. Erroneous key: %s"%key)
+			raise KeyCommandsError("%d, setting command: The keyboard shortcuts must be followed by a blank line. Multiple keys must be included in a table. Erroneous key: %s" % (self._lineno, key))
 
 		# Finally, the next line should be the description.
 		desc = next(self._ug).strip()
+		self._lineno += 1
 
 		self._kc.write(u"| {name} | {keys} | {desc} |{lineEnd}".format(
 			name=name,

