class_docstr: Read notebook cells from Sphinx Gallery scripts (#80)
class_docstr_tok: ["Read","notebook","cells","from","Sphinx","Gallery","scripts","(","#","80",")"]
docstr: Return position of end of cell, and position
  of first line after cell, and whether there was an
  explicit end of cell marker
docstr_tok: ["Return","position","of","end","of","cell",",","and","position","of","first","line","after","cell",",","and","whether","there","was","an","explicit","end","of","cell","marker"]
code: def find_cell_end(self, lines):
      """Return position of end of cell, and position
      of first line after cell, and whether there was an
      explicit end of cell marker"""
  
      if self.cell_type == "markdown":
          # Empty cell "" or ''
          if len(self.markdown_marker) <= 2:
              if len(lines) == 1 or _BLANK_LINE.match(lines[1]):
                  return 0, 2, True
              return 0, 1, True
  
          # Multi-line comment with triple quote
          if len(self.markdown_marker) == 3:
              for i, line in enumerate(lines):
                  if (
                      i > 0 or line.strip() != self.markdown_marker
                  ) and line.rstrip().endswith(self.markdown_marker):
                      explicit_end_of_cell_marker = (
                          line.strip() == self.markdown_marker
                      )
                      if explicit_end_of_cell_marker:
                          end_of_cell = i
                      else:
                          end_of_cell = i + 1
                      if len(lines) <= i + 1 or _BLANK_LINE.match(
                          lines[i + 1]
                      ):
                          return (
                              end_of_cell,
                              i + 2,
                              explicit_end_of_cell_marker,
                          )
                      return (
                          end_of_cell,
                          i + 1,
                          explicit_end_of_cell_marker,
                      )
          else:
              # 20 # or more
              for i, line in enumerate(lines[1:], 1):
                  if not line.startswith(self.comment):
                      if _BLANK_LINE.match(line):
                          return i, i + 1, False
                      return i, i, False
  
      elif self.cell_type == "code":
          parser = StringParser("python")
          for i, line in enumerate(lines):
              if parser.is_quoted():
                  parser.read_line(line)
                  continue
  
              if self.start_of_new_markdown_cell(line):
                  if i > 0 and _BLANK_LINE.match(lines[i - 1]):
                      return i - 1, i, False
                  return i, i, False
              parser.read_line(line)
  
      return len(lines), len(lines), False
  
imports: import re
  import warnings
  from copy import copy
  from nbformat.v4.nbbase import new_code_cell, new_markdown_cell, new_raw_cell
  from packaging.version import parse
  from .doxygen import doxygen_to_markdown
  from .languages import _SCRIPT_EXTENSIONS
  from .cell_metadata import is_active, is_json_metadata, rmd_options_to_metadata, text_to_metadata
  from .languages import _JUPYTER_LANGUAGES_LOWER_AND_UPPER
  from .magics import is_magic, need_explicit_marker, uncomment_magic, unescape_code_start
  from .pep8 import pep8_lines_between_cells
  from .stringparser import StringParser
label_desc: Use image node_id 4 for calling the SphinxGalleryScriptCellReader obj's underlying member method code with example usage: obj.find_cell_end(lines) and returns: len,  len,  False, int,  int,  True, int,  int,  True, end_of_cell,  unknown,  explicit_end_of_cell_marker, i,  i,  False, i,  i,  False, end_of_cell,  unknown,  explicit_end_of_cell_marker, i,  unknown,  False, unknown,  i,  False