bookmaker initial checkin
bookmaker is a tool that generates documentation backends from a canonical markup. Documentation for bookmaker itself is evolving at docs/usingBookmaker.bmh, which is visible online at skia.org/user/api/bmh_usingBookmaker Change-Id: Ic76ddf29134895b5c2ebfbc84603e40ff08caf09 Reviewed-on: https://skia-review.googlesource.com/28000 Commit-Queue: Cary Clark <caryclark@google.com> Reviewed-by: Cary Clark <caryclark@google.com>
This commit is contained in:
parent
acaa607328
commit
8032b983fa
17
BUILD.gn
17
BUILD.gn
@ -1213,6 +1213,23 @@ if (skia_enable_tools) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_app("bookmaker") {
|
||||||
|
sources = [
|
||||||
|
"tools/bookmaker/bookmaker.cpp",
|
||||||
|
"tools/bookmaker/fiddleParser.cpp",
|
||||||
|
"tools/bookmaker/includeParser.cpp",
|
||||||
|
"tools/bookmaker/includeWriter.cpp",
|
||||||
|
"tools/bookmaker/mdOut.cpp",
|
||||||
|
"tools/bookmaker/parserCommon.cpp",
|
||||||
|
"tools/bookmaker/spellCheck.cpp",
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
":flags",
|
||||||
|
":skia",
|
||||||
|
":tool_utils",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
import("gn/samples.gni")
|
import("gn/samples.gni")
|
||||||
test_lib("samples") {
|
test_lib("samples") {
|
||||||
public_include_dirs = [ "samplecode" ]
|
public_include_dirs = [ "samplecode" ]
|
||||||
|
5721
docs/SkCanvas.bmh
Normal file
5721
docs/SkCanvas.bmh
Normal file
File diff suppressed because it is too large
Load Diff
5280
docs/SkPaint.bmh
Normal file
5280
docs/SkPaint.bmh
Normal file
File diff suppressed because it is too large
Load Diff
5801
docs/SkPath.bmh
Normal file
5801
docs/SkPath.bmh
Normal file
File diff suppressed because it is too large
Load Diff
88
docs/markup.bmh
Normal file
88
docs/markup.bmh
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#Topic Bookmaker_Markup
|
||||||
|
|
||||||
|
# redefine markup character so examples below will not be parsed
|
||||||
|
###$
|
||||||
|
|
||||||
|
Text, except for the single markup character, requires no annotation.
|
||||||
|
|
||||||
|
# comments are preceded by a hash symbol and whitespace
|
||||||
|
# comments may terminated by linefeed or double hash ## <- end of comment
|
||||||
|
|
||||||
|
Keywords are preceded by a single hash symbol without whitespace.
|
||||||
|
#Keyword
|
||||||
|
|
||||||
|
Keywords are terminated by double hash and may be labeled
|
||||||
|
## <- end of #keyword
|
||||||
|
|
||||||
|
#Keyword
|
||||||
|
#Keyword ## <- alternate labeled end of #Keyword
|
||||||
|
|
||||||
|
Tables use single hash symbols to delimit columns, and double to end row.
|
||||||
|
#Table
|
||||||
|
#Legend
|
||||||
|
# first column in table # next column in table ##
|
||||||
|
## <- end of #Legend
|
||||||
|
# a row # another row ##
|
||||||
|
# another row # another row ##
|
||||||
|
#Table ## <- or, just ##
|
||||||
|
|
||||||
|
$Table
|
||||||
|
$Legend
|
||||||
|
$ first column in table $ next column in table $$
|
||||||
|
$$
|
||||||
|
$ a row $ another row $$
|
||||||
|
$ another row $ another row $$
|
||||||
|
$Table $$
|
||||||
|
|
||||||
|
The markup character is initially # at the start of any .bmh file
|
||||||
|
###x <- redefine the markup character as 'x'
|
||||||
|
xxx# <- restore the default markup character
|
||||||
|
|
||||||
|
anchor, ala HTML
|
||||||
|
anchors may start anywhere in the line
|
||||||
|
#A text #_reference ##
|
||||||
|
|
||||||
|
class description
|
||||||
|
#Class SkClassName
|
||||||
|
description
|
||||||
|
methods
|
||||||
|
##
|
||||||
|
|
||||||
|
if the example is not named, it inherits the name of its container
|
||||||
|
#Example
|
||||||
|
#Description
|
||||||
|
##
|
||||||
|
#Image
|
||||||
|
#Width
|
||||||
|
#Height
|
||||||
|
code...
|
||||||
|
#StdOut
|
||||||
|
expected example output
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Enum __required_reference
|
||||||
|
description
|
||||||
|
#Code
|
||||||
|
##
|
||||||
|
#Example
|
||||||
|
##
|
||||||
|
#Enum ##
|
||||||
|
|
||||||
|
method description
|
||||||
|
the _method_reference must be unique within the class
|
||||||
|
#Method type name(params..)
|
||||||
|
description
|
||||||
|
#Param name description ##
|
||||||
|
#Return return ##
|
||||||
|
#Example
|
||||||
|
##
|
||||||
|
#SeeAlso ##
|
||||||
|
##
|
||||||
|
|
||||||
|
#ToDo description ##
|
||||||
|
|
||||||
|
$ restore markup character
|
||||||
|
$$$#
|
||||||
|
|
||||||
|
##
|
8
docs/overview.bmh
Normal file
8
docs/overview.bmh
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
overview
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Skia draws 2D primitives, paths and bitmaps, using the styles in the SkPaint, to
|
||||||
|
the device contained by the SkCanvas.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
528
docs/undocumented.bmh
Normal file
528
docs/undocumented.bmh
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
# external references that will be documented eventually ...
|
||||||
|
#External
|
||||||
|
DirectWrite TrueType Windows Linux Android
|
||||||
|
FreeType FreeType-based Harfbuzz
|
||||||
|
PostScript PostScript_arct
|
||||||
|
OS_X Core_Graphics Core_Text iOS
|
||||||
|
LCD RGB
|
||||||
|
Premultiplied Unpremultiplied
|
||||||
|
Unicode Unicode5 UTF-8 UTF-16 UTF-32 ASCII Unichar
|
||||||
|
HTML_Canvas HTML_Canvas_arcTo
|
||||||
|
API
|
||||||
|
CPU
|
||||||
|
GPU GPU-backed GPU_Context OpenGL Vulkan
|
||||||
|
NULL
|
||||||
|
RFC
|
||||||
|
Bezier Coons
|
||||||
|
SkUserConfig.h # not external, but still thinking about how markup refers to this
|
||||||
|
Skia # ditto
|
||||||
|
SK_USE_FREETYPE_EMBOLDEN # ditto
|
||||||
|
SK_SUPPORT_LEGACY_PAINT_TEXTDECORATION # ditto
|
||||||
|
SK_BUILD_FOR_ANDROID_FRAMEWORK # ditto
|
||||||
|
Developer_Mode # ditto
|
||||||
|
Draw_Layer # ditto
|
||||||
|
Raster_Engine # ditto
|
||||||
|
|
||||||
|
# FreeType related
|
||||||
|
FT_LOAD_TARGET_LIGHT
|
||||||
|
FT_LOAD_TARGET_NORMAL
|
||||||
|
FT_LOAD_TARGET_LCD
|
||||||
|
FT_LOAD_TARGET_LCD_V
|
||||||
|
FT_LOAD_NO_HINTING
|
||||||
|
FT_Load_Glyph
|
||||||
|
|
||||||
|
#External ##
|
||||||
|
|
||||||
|
#Topic Arc
|
||||||
|
#Substitute arcs
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic BBH_Factory
|
||||||
|
#Class SkBBHFactory
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Bitmap
|
||||||
|
#Class SkBitmap
|
||||||
|
#Subtopic Row_Bytes
|
||||||
|
##
|
||||||
|
#Class ##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Blend_Mode
|
||||||
|
#EnumClass SkBlendMode
|
||||||
|
#Const kSrc 1
|
||||||
|
##
|
||||||
|
#Const kSrcOver 3
|
||||||
|
##
|
||||||
|
#Const kPlus 12
|
||||||
|
##
|
||||||
|
#EnumClass ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Circle
|
||||||
|
#Substitute circles
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Clip_Op
|
||||||
|
#EnumClass SkClipOp
|
||||||
|
#Const kDifference 0
|
||||||
|
##
|
||||||
|
#Const kIntersect 1
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Color
|
||||||
|
#Typedef SkColor
|
||||||
|
#Typedef ##
|
||||||
|
|
||||||
|
# fixme: defines, not methods, need new markup type
|
||||||
|
#Method int SkColorGetA(color)
|
||||||
|
##
|
||||||
|
#Method int SkColorGetR(color)
|
||||||
|
##
|
||||||
|
#Method int SkColorGetG(color)
|
||||||
|
##
|
||||||
|
#Method int SkColorGetB(color)
|
||||||
|
##
|
||||||
|
#Method int SkColorSetARGB(a, r, g, b)
|
||||||
|
##
|
||||||
|
|
||||||
|
#Const SK_ColorBLACK 0xFF000000
|
||||||
|
##
|
||||||
|
#Const SK_ColorBLUE 0xFF0000FF
|
||||||
|
##
|
||||||
|
#Const SK_ColorGREEN 0xFF00FF00
|
||||||
|
##
|
||||||
|
#Const SK_ColorRED 0xFFFF0000
|
||||||
|
##
|
||||||
|
#Const SK_ColorWHITE 0xFFFFFFFF
|
||||||
|
##
|
||||||
|
#Subtopic Alpha
|
||||||
|
#Substitute alpha
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic RGB
|
||||||
|
#Substitute RGB
|
||||||
|
#Subtopic Red
|
||||||
|
#Substitute red
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic Blue
|
||||||
|
#Substitute blue
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic Green
|
||||||
|
#Substitute green
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic ARGB
|
||||||
|
#Substitute ARGB
|
||||||
|
#Subtopic ##
|
||||||
|
|
||||||
|
#Subtopic RBG
|
||||||
|
#Substitute RBG
|
||||||
|
#Subtopic ##
|
||||||
|
|
||||||
|
#Subtopic RGB-565
|
||||||
|
#Substitute RGB-565
|
||||||
|
#Alias Color_RGB-565 # quit changing - to _ !
|
||||||
|
#Subtopic ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Color_Filter
|
||||||
|
#Class SkColorFilter
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Color_Space
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Curve
|
||||||
|
#Alias Curves
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Data
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Device
|
||||||
|
#Class SkBaseDevice
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Document
|
||||||
|
#Class SkDocument
|
||||||
|
#Method SkCanvas* beginPage(SkScalar width, SkScalar height,
|
||||||
|
const SkRect* content = NULL)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Subtopic PDF
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Draw_Filter
|
||||||
|
#Class SkDrawFilter
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Draw_Looper
|
||||||
|
#Class SkDrawLooper
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Drawable
|
||||||
|
#Class SkDrawable
|
||||||
|
#Method void draw(SkCanvas*, const SkMatrix* = NULL)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Dump_Canvas
|
||||||
|
#Class SkDumpCanvas
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Filter_Quality
|
||||||
|
#Enum SkFilterQuality
|
||||||
|
#Const kNone_SkFilterQuality 0
|
||||||
|
##
|
||||||
|
#Const kLow_SkFilterQuality 1
|
||||||
|
##
|
||||||
|
#Const kMedium_SkFilterQuality 2
|
||||||
|
##
|
||||||
|
#Const kHigh_SkFilterQuality 3
|
||||||
|
##
|
||||||
|
#Enum ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Font
|
||||||
|
#Subtopic Advance
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic Engine
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Font_Manager
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Glyph
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Image
|
||||||
|
#Subtopic Alpha_Type
|
||||||
|
#Enum SkAlphaType
|
||||||
|
#Const kPremul_SkAlphaType 2
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic Color_Type
|
||||||
|
#Enum SkColorType
|
||||||
|
#Const kUnknown_SkColorType 0
|
||||||
|
##
|
||||||
|
#Const kAlpha_8_SkColorType 1
|
||||||
|
##
|
||||||
|
#Const kRGB_565_SkColorType 2
|
||||||
|
##
|
||||||
|
#Const kARGB_4444_SkColorType 3
|
||||||
|
##
|
||||||
|
#Const kRGBA_8888_SkColorType 4
|
||||||
|
##
|
||||||
|
#Const kBGRA_8888_SkColorType 5
|
||||||
|
##
|
||||||
|
#Const kIndex_8_SkColorType 6
|
||||||
|
##
|
||||||
|
#Const kGray_8_SkColorType 7
|
||||||
|
##
|
||||||
|
#Const kRGBA_F16_SkColorType 8
|
||||||
|
##
|
||||||
|
#ToDo this is a lie; need to not require values for consts ##
|
||||||
|
#Const kN32_SkColorType 4
|
||||||
|
##
|
||||||
|
#Enum ##
|
||||||
|
#Subtopic ##
|
||||||
|
#Subtopic Info
|
||||||
|
#Struct SkImageInfo
|
||||||
|
#Method SkImageInfo()
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Subtopic ##
|
||||||
|
#Class SkImage
|
||||||
|
#Method sk_sp<SkShader> makeShader(SkShader::TileMode, SkShader::TileMode,
|
||||||
|
const SkMatrix* localMatrix = nullptr) const
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Image_Filter
|
||||||
|
#Subtopic Scaling
|
||||||
|
#Subtopic ##
|
||||||
|
#Class SkImageFilter
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Image_Scaling
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic IRect
|
||||||
|
#Struct SkIRect
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Line
|
||||||
|
#Substitute lines
|
||||||
|
#Alias Lines
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Mask
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Mask_Alpha
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Mask_Filter
|
||||||
|
#Class SkMaskFilter
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Matrix
|
||||||
|
#Struct SkMatrix
|
||||||
|
#Struct ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Nine_Patch
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Number_Types
|
||||||
|
#Typedef SkGlyphID
|
||||||
|
#Typedef ##
|
||||||
|
#Typedef SkScalar
|
||||||
|
#Typedef ##
|
||||||
|
#Const SK_ScalarMax
|
||||||
|
to be written
|
||||||
|
##
|
||||||
|
#Const SK_ScalarInfinity
|
||||||
|
to be written
|
||||||
|
##
|
||||||
|
#Const SK_ScalarNegativeInfinity
|
||||||
|
to be written
|
||||||
|
##
|
||||||
|
#Const SK_ScalarNaN
|
||||||
|
to be written
|
||||||
|
##
|
||||||
|
#Typedef SkUnichar
|
||||||
|
#Typedef ##
|
||||||
|
#Typedef U8CPU
|
||||||
|
#Typedef ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Oval
|
||||||
|
#Substitute ovals
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Paint_Defaults
|
||||||
|
#Const SkPaintDefaults_Flags 0
|
||||||
|
##
|
||||||
|
#Const SkPaintDefaults_Hinting 2
|
||||||
|
##
|
||||||
|
#Const SkPaintDefaults_TextSize 12
|
||||||
|
##
|
||||||
|
#Const SkPaintDefaults_MiterLimit 4
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Patch
|
||||||
|
#Substitute patches
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Path_Effect
|
||||||
|
#Class SkPathEffect
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Path_Measure
|
||||||
|
#Class SkPathMeasure
|
||||||
|
#Method void dump() const
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic PathOps
|
||||||
|
#Method bool SK_API Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result)
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Picture
|
||||||
|
#Subtopic Recorder
|
||||||
|
#Class SkPictureRecorder
|
||||||
|
#Method SkCanvas* beginRecording(const SkRect& bounds,
|
||||||
|
SkBBHFactory* bbhFactory = NULL,
|
||||||
|
uint32_t recordFlags = 0)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Pixel
|
||||||
|
#Subtopic Storage
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Pixmap
|
||||||
|
#Class SkPixmap
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Point
|
||||||
|
#Alias Points
|
||||||
|
#Struct SkPoint
|
||||||
|
#Method bool equalsWithinTolerance(const SkPoint& p) const
|
||||||
|
##
|
||||||
|
#Struct ##
|
||||||
|
#Subtopic Array
|
||||||
|
#Substitute SkPoint arrays
|
||||||
|
#Subtopic ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Raster_Handle_Allocator
|
||||||
|
#Class SkRasterHandleAllocator
|
||||||
|
#Struct Rec
|
||||||
|
##
|
||||||
|
#Method static std::unique_ptr<SkCanvas> MakeCanvas(std::unique_ptr<SkRasterHandleAllocator>, const SkImageInfo&, const Rec* rec = nullptr)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Rasterizer
|
||||||
|
#Class SkRasterizer
|
||||||
|
#Class ##
|
||||||
|
#Subtopic Layer
|
||||||
|
#Subtopic ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Rect
|
||||||
|
#Alias Rects
|
||||||
|
#Struct SkRect
|
||||||
|
#Method static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty()
|
||||||
|
##
|
||||||
|
#Method void dump() const
|
||||||
|
##
|
||||||
|
#Method void dumpHex() const
|
||||||
|
##
|
||||||
|
#Struct ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Reference_Count
|
||||||
|
#Substitute SkRefCnt
|
||||||
|
#Class sk_sp
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Region
|
||||||
|
#Class SkRegion
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Round_Rect
|
||||||
|
#Class SkRRect
|
||||||
|
#Method void dump() const
|
||||||
|
##
|
||||||
|
#Method void dumpHex() const
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic RSXform
|
||||||
|
#Struct SkRSXform
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Shader
|
||||||
|
#Class SkShader
|
||||||
|
#Enum TileMode
|
||||||
|
#Const kClamp_TileMode 0
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Method static sk_sp<SkShader> MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
|
||||||
|
const SkMatrix* localMatrix = nullptr)
|
||||||
|
##
|
||||||
|
#Class ##
|
||||||
|
#Subtopic Gradient
|
||||||
|
#Subtopic ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Sprite
|
||||||
|
#Substitute sprites
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Stream
|
||||||
|
#Class SkFlattenable
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic String
|
||||||
|
#Class SkString
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Surface
|
||||||
|
#Class SkSurface
|
||||||
|
#Method static sk_sp<SkSurface> MakeRasterDirect(const SkImageInfo&, void* pixels, size_t rowBytes,
|
||||||
|
const SkSurfaceProps* = nullptr)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Subtopic Properties
|
||||||
|
#Class SkSurfaceProps
|
||||||
|
#Enum InitType
|
||||||
|
#Const kLegacyFontHost_InitType 0
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
##
|
||||||
|
#Subtopic GPU
|
||||||
|
#Alias GPU_Surface
|
||||||
|
##
|
||||||
|
#Subtopic Raster
|
||||||
|
#Alias Raster_Surface
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic SVG
|
||||||
|
#Subtopic Canvas
|
||||||
|
##
|
||||||
|
#Subtopic Arc
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Text
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Text_Blob
|
||||||
|
#Class SkTextBlob
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Typeface
|
||||||
|
#Class SkTypeface
|
||||||
|
#Class ##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Vector
|
||||||
|
#Struct SkVector
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Vertices
|
||||||
|
#Substitute vertices
|
||||||
|
#Subtopic Colors
|
||||||
|
##
|
||||||
|
#Subtopic Texs
|
||||||
|
##
|
||||||
|
#Topic ##
|
||||||
|
|
||||||
|
#Topic Read_Buffer
|
||||||
|
#Struct SkReadBuffer
|
||||||
|
#Struct ##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Write_Buffer
|
||||||
|
#Struct SkWriteBuffer
|
||||||
|
#Struct ##
|
||||||
|
#Topic ##
|
95
docs/usingBookmaker.bmh
Normal file
95
docs/usingBookmaker.bmh
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#External
|
||||||
|
SkXXX
|
||||||
|
bmh_SkXXX
|
||||||
|
CL
|
||||||
|
C
|
||||||
|
Visual_Studio
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Bookmaker
|
||||||
|
|
||||||
|
How to use the Bookmaker utility.
|
||||||
|
|
||||||
|
Get the fiddle command line interface tool.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ go get go.skia.org/infra/fiddle/go/fiddlecli
|
||||||
|
##
|
||||||
|
|
||||||
|
Get the Bookmaker CL and build it.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ git cl patch 9919
|
||||||
|
$ ninja -C out/dir bookmaker
|
||||||
|
##
|
||||||
|
|
||||||
|
Generate an starter Bookmaker file from an existing include.
|
||||||
|
This writes SkXXX.bmh in the current directory, which is
|
||||||
|
out/dir/obj/ from an IDE.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ ./out/dir/bookmaker -t -i include/core/SkXXX.h
|
||||||
|
##
|
||||||
|
|
||||||
|
Use your favorite editor to fill out SkXXX.bmh.
|
||||||
|
|
||||||
|
Generate fiddle.json from all examples, including the ones you just wrote.
|
||||||
|
Error checking is syntatic: starting keywords are closed, keywords have the
|
||||||
|
correct parents.
|
||||||
|
If you run Bookmaker inside Visual_Studio, you can click on errors and it
|
||||||
|
will take you to the source line in question.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ ./out/dir/bookmaker -e fiddle.json -b current_directory
|
||||||
|
##
|
||||||
|
|
||||||
|
Once complete, run fiddlecli to generate the example hashes.
|
||||||
|
Errors are contained by the output but aren't reported yet.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ $GOPATH/bin/fiddlecli --input fiddle.json --output fiddleout.json
|
||||||
|
##
|
||||||
|
|
||||||
|
Generate bmh_SkXXX.md from SkXXX.bmh and fiddleout.json.
|
||||||
|
Error checking includes: undefined references, fiddle compiler errors,
|
||||||
|
missing or mismatched printf output.
|
||||||
|
Again, you can click on any errors inside Visual_Studio.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ ./out/dir/bookmaker -r site/user/api -b current_directory -f fiddleout.json
|
||||||
|
##
|
||||||
|
|
||||||
|
The original include may have changed since you started creating the markdown.
|
||||||
|
Check to see if it is up to date.
|
||||||
|
This reports if a method no longer exists or its parameters have changed.
|
||||||
|
|
||||||
|
#Code
|
||||||
|
$ ./out/dir/bookmaker -x -b current_directory/SkXXX.bmh -i include/core/SkXXX.h
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Bugs
|
||||||
|
#List
|
||||||
|
overaggressive reference finding in code block
|
||||||
|
missing examples
|
||||||
|
redundant examples -- got tired so used the same one more than once
|
||||||
|
some examples need vertical resizing
|
||||||
|
list doesn't work (ironic, huh)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic To_Do
|
||||||
|
#List
|
||||||
|
check that all methods have one line descriptions in overview
|
||||||
|
see also -- anything that can be done automatically? maybe any ref shows up everywhere
|
||||||
|
index by example png
|
||||||
|
generate pdf or pdf-like out
|
||||||
|
generate b/w out instead of color -- have b/w versions of examples?
|
||||||
|
formalize voice / syntax for parts of topic and method
|
||||||
|
write bmh data back into include
|
||||||
|
have a way to write one block that covers multiple nearly indentical methods?
|
||||||
|
may want to do this for pdf view as well
|
||||||
|
write a one-method-per-page online view?
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
|
#Topic Bookmaker ##
|
2198
tools/bookmaker/bookmaker.cpp
Normal file
2198
tools/bookmaker/bookmaker.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1844
tools/bookmaker/bookmaker.h
Normal file
1844
tools/bookmaker/bookmaker.h
Normal file
File diff suppressed because it is too large
Load Diff
231
tools/bookmaker/fiddleParser.cpp
Normal file
231
tools/bookmaker/fiddleParser.cpp
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bookmaker.h"
|
||||||
|
|
||||||
|
static Definition* find_fiddle(Definition* def, const string& name) {
|
||||||
|
if (MarkType::kExample == def->fMarkType && name == def->fFiddle) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
for (auto& child : def->fChildren) {
|
||||||
|
Definition* result = find_fiddle(child, name);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Definition* FiddleParser::findExample(const string& name) const {
|
||||||
|
for (const auto& topic : fBmhParser->fTopicMap) {
|
||||||
|
if (topic.second->fParent) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Definition* def = find_fiddle(topic.second, name);
|
||||||
|
if (def) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FiddleParser::parseFiddles() {
|
||||||
|
if (!this->skipExact("{\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (!this->eof()) {
|
||||||
|
if (!this->skipExact(" \"")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char* nameLoc = fChar;
|
||||||
|
if (!this->skipToEndBracket("\"")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string name(nameLoc, fChar - nameLoc);
|
||||||
|
if (!this->skipExact("\": {\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->skipExact(" \"compile_errors\": [")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (']' != this->peek()) {
|
||||||
|
// report compiler errors
|
||||||
|
int brackets = 1;
|
||||||
|
const char* errorStart = fChar;
|
||||||
|
do {
|
||||||
|
if ('[' == this->peek()) {
|
||||||
|
++brackets;
|
||||||
|
} else if (']' == this->peek()) {
|
||||||
|
--brackets;
|
||||||
|
}
|
||||||
|
} while (!this->eof() && this->next() && brackets > 0);
|
||||||
|
SkDebugf("fiddle compile error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
|
||||||
|
errorStart);
|
||||||
|
}
|
||||||
|
if (!this->skipExact("],\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->skipExact(" \"runtime_error\": \"")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ('"' != this->peek()) {
|
||||||
|
const char* errorStart = fChar;
|
||||||
|
if (!this->skipToEndBracket('"')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SkDebugf("fiddle runtime error in %s: %.*s\n", name.c_str(), (int) (fChar - errorStart),
|
||||||
|
errorStart);
|
||||||
|
}
|
||||||
|
if (!this->skipExact("\",\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->skipExact(" \"fiddleHash\": \"")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char* hashStart = fChar;
|
||||||
|
if (!this->skipToEndBracket('"')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Definition* example = this->findExample(name);
|
||||||
|
if (!example) {
|
||||||
|
SkDebugf("missing example %s\n", name.c_str());
|
||||||
|
}
|
||||||
|
string hash(hashStart, fChar - hashStart);
|
||||||
|
if (example) {
|
||||||
|
example->fHash = hash;
|
||||||
|
}
|
||||||
|
if (!this->skipExact("\",\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->skipExact(" \"text\": \"")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ('"' != this->peek()) {
|
||||||
|
const char* stdOutStart = fChar;
|
||||||
|
do {
|
||||||
|
if ('\\' == this->peek()) {
|
||||||
|
this->next();
|
||||||
|
} else if ('"' == this->peek()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (!this->eof() && this->next());
|
||||||
|
const char* stdOutEnd = fChar;
|
||||||
|
if (example) {
|
||||||
|
bool foundStdOut = false;
|
||||||
|
for (auto& textOut : example->fChildren) {
|
||||||
|
if (MarkType::kStdOut != textOut->fMarkType) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foundStdOut = true;
|
||||||
|
bool foundVolatile = false;
|
||||||
|
for (auto& stdOutChild : textOut->fChildren) {
|
||||||
|
if (MarkType::kVolatile == stdOutChild->fMarkType) {
|
||||||
|
foundVolatile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextParser bmh(textOut);
|
||||||
|
EscapeParser fiddle(stdOutStart, stdOutEnd);
|
||||||
|
do {
|
||||||
|
bmh.skipWhiteSpace();
|
||||||
|
fiddle.skipWhiteSpace();
|
||||||
|
const char* bmhEnd = bmh.trimmedLineEnd();
|
||||||
|
const char* fiddleEnd = fiddle.trimmedLineEnd();
|
||||||
|
ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
|
||||||
|
SkASSERT(bmhLen > 0);
|
||||||
|
ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
|
||||||
|
SkASSERT(fiddleLen > 0);
|
||||||
|
if (bmhLen != fiddleLen) {
|
||||||
|
if (!foundVolatile) {
|
||||||
|
SkDebugf("mismatched stdout len in %s\n", name.c_str());
|
||||||
|
}
|
||||||
|
} else if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
|
||||||
|
if (!foundVolatile) {
|
||||||
|
SkDebugf("mismatched stdout text in %s\n", name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bmh.skipToLineStart();
|
||||||
|
fiddle.skipToLineStart();
|
||||||
|
} while (!bmh.eof() && !fiddle.eof());
|
||||||
|
if (!foundStdOut) {
|
||||||
|
SkDebugf("bmh %s missing stdout\n", name.c_str());
|
||||||
|
} else if (!bmh.eof() || !fiddle.eof()) {
|
||||||
|
if (!foundVolatile) {
|
||||||
|
SkDebugf("%s mismatched stdout eof\n", name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this->skipExact("\"\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->skipExact(" }")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ('\n' == this->peek()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!this->skipExact(",\n")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
// compare the text output with the expected output in the markup tree
|
||||||
|
this->skipToSpace();
|
||||||
|
SkASSERT(' ' == fChar[0]);
|
||||||
|
this->next();
|
||||||
|
const char* nameLoc = fChar;
|
||||||
|
this->skipToNonAlphaNum();
|
||||||
|
const char* nameEnd = fChar;
|
||||||
|
string name(nameLoc, nameEnd - nameLoc);
|
||||||
|
const Definition* example = this->findExample(name);
|
||||||
|
if (!example) {
|
||||||
|
return this->reportError<bool>("missing stdout name");
|
||||||
|
}
|
||||||
|
SkASSERT(':' == fChar[0]);
|
||||||
|
this->next();
|
||||||
|
this->skipSpace();
|
||||||
|
const char* stdOutLoc = fChar;
|
||||||
|
do {
|
||||||
|
this->skipToLineStart();
|
||||||
|
} while (!this->eof() && !this->startsWith("fiddles.htm:"));
|
||||||
|
const char* stdOutEnd = fChar;
|
||||||
|
for (auto& textOut : example->fChildren) {
|
||||||
|
if (MarkType::kStdOut != textOut->fMarkType) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TextParser bmh(textOut);
|
||||||
|
TextParser fiddle(fFileName, stdOutLoc, stdOutEnd, fLineCount);
|
||||||
|
do {
|
||||||
|
bmh.skipWhiteSpace();
|
||||||
|
fiddle.skipWhiteSpace();
|
||||||
|
const char* bmhEnd = bmh.trimmedLineEnd();
|
||||||
|
const char* fiddleEnd = fiddle.trimmedLineEnd();
|
||||||
|
ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
|
||||||
|
SkASSERT(bmhLen > 0);
|
||||||
|
ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
|
||||||
|
SkASSERT(fiddleLen > 0);
|
||||||
|
if (bmhLen != fiddleLen) {
|
||||||
|
return this->reportError<bool>("mismatched stdout len");
|
||||||
|
}
|
||||||
|
if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
|
||||||
|
return this->reportError<bool>("mismatched stdout text");
|
||||||
|
}
|
||||||
|
bmh.skipToLineStart();
|
||||||
|
fiddle.skipToLineStart();
|
||||||
|
} while (!bmh.eof() && !fiddle.eof());
|
||||||
|
if (!bmh.eof() || (!fiddle.eof() && !fiddle.startsWith("</pre>"))) {
|
||||||
|
return this->reportError<bool>("mismatched stdout eof");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
1733
tools/bookmaker/includeParser.cpp
Normal file
1733
tools/bookmaker/includeParser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1272
tools/bookmaker/includeWriter.cpp
Normal file
1272
tools/bookmaker/includeWriter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
929
tools/bookmaker/mdOut.cpp
Normal file
929
tools/bookmaker/mdOut.cpp
Normal file
@ -0,0 +1,929 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bookmaker.h"
|
||||||
|
|
||||||
|
#include "SkOSFile.h"
|
||||||
|
#include "SkOSPath.h"
|
||||||
|
|
||||||
|
static void add_ref(const string& leadingSpaces, const string& ref, string* result) {
|
||||||
|
*result += leadingSpaces + ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: preserve inter-line spaces and don't add new ones
|
||||||
|
string MdOut::addReferences(const char* refStart, const char* refEnd,
|
||||||
|
BmhParser::Resolvable resolvable) {
|
||||||
|
string result;
|
||||||
|
MethodParser t(fRoot ? fRoot->fName : string(), fFileName, refStart, refEnd, fLineCount);
|
||||||
|
bool lineStart = true;
|
||||||
|
string ref;
|
||||||
|
string leadingSpaces;
|
||||||
|
do {
|
||||||
|
const char* base = t.fChar;
|
||||||
|
t.skipWhiteSpace();
|
||||||
|
const char* wordStart = t.fChar;
|
||||||
|
t.skipToMethodStart();
|
||||||
|
const char* start = t.fChar;
|
||||||
|
if (wordStart < start) {
|
||||||
|
if (lineStart) {
|
||||||
|
lineStart = false;
|
||||||
|
} else {
|
||||||
|
wordStart = base;
|
||||||
|
}
|
||||||
|
result += string(wordStart, start - wordStart);
|
||||||
|
if ('\n' != result.back()) {
|
||||||
|
while (start > wordStart && '\n' == start[-1]) {
|
||||||
|
result += '\n';
|
||||||
|
--start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lineStart) {
|
||||||
|
lineStart = false;
|
||||||
|
} else {
|
||||||
|
leadingSpaces = string(base, wordStart - base);
|
||||||
|
}
|
||||||
|
t.skipToMethodEnd();
|
||||||
|
if (base == t.fChar) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (start >= t.fChar) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!t.eof() && '"' == t.peek() && start > wordStart && '"' == start[-1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ref = string(start, t.fChar - start);
|
||||||
|
if (const Definition* def = this->isDefined(t, ref,
|
||||||
|
BmhParser::Resolvable::kOut != resolvable)) {
|
||||||
|
SkASSERT(def->fFiddle.length());
|
||||||
|
if (!t.eof() && '(' == t.peek() && t.strnchr(')', t.fEnd)) {
|
||||||
|
if (!t.skipToEndBracket(')')) {
|
||||||
|
t.reportError("missing close paren");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
t.next();
|
||||||
|
string fullRef = string(start, t.fChar - start);
|
||||||
|
// if _2 etc alternates are defined, look for paren match
|
||||||
|
// may ignore () if ref is all lower case
|
||||||
|
// otherwise flag as error
|
||||||
|
int suffix = '2';
|
||||||
|
bool foundMatch = false;
|
||||||
|
const Definition* altDef = def;
|
||||||
|
while (altDef && suffix <= '9') {
|
||||||
|
if ((foundMatch = altDef->paramsMatch(fullRef, ref))) {
|
||||||
|
def = altDef;
|
||||||
|
ref = fullRef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
string altTest = ref + '_';
|
||||||
|
altTest += suffix++;
|
||||||
|
altDef = this->isDefined(t, altTest, false);
|
||||||
|
}
|
||||||
|
if (suffix > '9') {
|
||||||
|
t.reportError("too many alts");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (!foundMatch) {
|
||||||
|
if (!(def = this->isDefined(t, fullRef, true))) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ref = fullRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += linkRef(leadingSpaces, def, ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!t.eof() && '(' == t.peek()) {
|
||||||
|
if (!t.skipToEndBracket(')')) {
|
||||||
|
t.reportError("missing close paren");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
t.next();
|
||||||
|
ref = string(start, t.fChar - start);
|
||||||
|
if (const Definition* def = this->isDefined(t, ref, true)) {
|
||||||
|
SkASSERT(def->fFiddle.length());
|
||||||
|
result += linkRef(leadingSpaces, def, ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// class, struct, and enum start with capitals
|
||||||
|
// methods may start with upper (static) or lower (most)
|
||||||
|
|
||||||
|
// see if this should have been a findable reference
|
||||||
|
|
||||||
|
// look for Sk / sk / SK ..
|
||||||
|
if (!ref.compare(0, 2, "Sk") && ref != "Skew" && ref != "Skews" &&
|
||||||
|
ref != "Skip" && ref != "Skips") {
|
||||||
|
t.reportError("missed Sk prefixed");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (!ref.compare(0, 2, "SK")) {
|
||||||
|
if (BmhParser::Resolvable::kOut != resolvable) {
|
||||||
|
t.reportError("missed SK prefixed");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (!isupper(start[0])) {
|
||||||
|
// TODO:
|
||||||
|
// look for all lowercase w/o trailing parens as mistaken method matches
|
||||||
|
// will also need to see if Example Description matches var in example
|
||||||
|
const Definition* def;
|
||||||
|
if (fMethod && (def = fMethod->hasParam(ref))) {
|
||||||
|
result += linkRef(leadingSpaces, def, ref);
|
||||||
|
continue;
|
||||||
|
} else if (!fInDescription && ref[0] != '0'
|
||||||
|
&& string::npos != ref.find_first_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
|
||||||
|
// FIXME: see isDefined(); check to see if fXX is a member of xx.fXX
|
||||||
|
if (('f' != ref[0] && string::npos == ref.find("()"))
|
||||||
|
|| '.' != t.backup(ref.c_str())) {
|
||||||
|
if (BmhParser::Resolvable::kOut != resolvable) {
|
||||||
|
t.reportError("missed camelCase");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_ref(leadingSpaces, ref, &result);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto topicIter = fBmhParser.fTopicMap.find(ref);
|
||||||
|
if (topicIter != fBmhParser.fTopicMap.end()) {
|
||||||
|
result += linkRef(leadingSpaces, topicIter->second, ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool startsSentence = t.sentenceEnd(start);
|
||||||
|
if (!t.eof() && ' ' != t.peek()) {
|
||||||
|
add_ref(leadingSpaces, ref, &result);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (t.fChar + 1 >= t.fEnd || (!isupper(t.fChar[1]) && startsSentence)) {
|
||||||
|
add_ref(leadingSpaces, ref, &result);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isupper(t.fChar[1]) && startsSentence) {
|
||||||
|
TextParser next(t.fFileName, &t.fChar[1], t.fEnd, t.fLineCount);
|
||||||
|
string nextWord(next.fChar, next.wordEnd() - next.fChar);
|
||||||
|
if (this->isDefined(t, nextWord, true)) {
|
||||||
|
add_ref(leadingSpaces, ref, &result);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Definition* test = fRoot;
|
||||||
|
do {
|
||||||
|
if (!test->isRoot()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (string prefix : { "_", "::" } ) {
|
||||||
|
RootDefinition* root = test->asRoot();
|
||||||
|
string prefixed = root->fName + prefix + ref;
|
||||||
|
if (const Definition* def = root->find(prefixed)) {
|
||||||
|
result += linkRef(leadingSpaces, def, ref);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ((test = test->fParent));
|
||||||
|
found:
|
||||||
|
if (!test) {
|
||||||
|
if (BmhParser::Resolvable::kOut != resolvable) {
|
||||||
|
t.reportError("undefined reference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!t.eof());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MdOut::buildReferences(const char* fileOrPath, const char* outDir) {
|
||||||
|
if (!sk_isdir(fileOrPath)) {
|
||||||
|
if (!this->buildRefFromFile(fileOrPath, outDir)) {
|
||||||
|
SkDebugf("failed to parse %s\n", fileOrPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SkOSFile::Iter it(fileOrPath, ".bmh");
|
||||||
|
for (SkString file; it.next(&file); ) {
|
||||||
|
SkString p = SkOSPath::Join(fileOrPath, file.c_str());
|
||||||
|
const char* hunk = p.c_str();
|
||||||
|
if (!SkStrEndsWith(hunk, ".bmh")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (SkStrEndsWith(hunk, "markup.bmh")) { // don't look inside this for now
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!this->buildRefFromFile(hunk, outDir)) {
|
||||||
|
SkDebugf("failed to parse %s\n", hunk);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MdOut::buildRefFromFile(const char* name, const char* outDir) {
|
||||||
|
fFileName = string(name);
|
||||||
|
string filename(name);
|
||||||
|
if (filename.substr(filename.length() - 4) == ".bmh") {
|
||||||
|
filename = filename.substr(0, filename.length() - 4);
|
||||||
|
}
|
||||||
|
size_t start = filename.length();
|
||||||
|
while (start > 0 && (isalnum(filename[start - 1]) || '_' == filename[start - 1])) {
|
||||||
|
--start;
|
||||||
|
}
|
||||||
|
string match = filename.substr(start);
|
||||||
|
string header = match;
|
||||||
|
filename = "bmh_" + match + ".md";
|
||||||
|
match += ".bmh";
|
||||||
|
fOut = nullptr;
|
||||||
|
for (const auto& topic : fBmhParser.fTopicMap) {
|
||||||
|
Definition* topicDef = topic.second;
|
||||||
|
if (topicDef->fParent) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!topicDef->isRoot()) {
|
||||||
|
return this->reportError<bool>("expected root topic");
|
||||||
|
}
|
||||||
|
fRoot = topicDef->asRoot();
|
||||||
|
if (string::npos == fRoot->fFileName.rfind(match)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!fOut) {
|
||||||
|
string fullName(outDir);
|
||||||
|
if ('/' != fullName.back()) {
|
||||||
|
fullName += '/';
|
||||||
|
}
|
||||||
|
fullName += filename;
|
||||||
|
fOut = fopen(fullName.c_str(), "wb");
|
||||||
|
if (!fOut) {
|
||||||
|
SkDebugf("could not open output file %s\n", fullName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fprintf(fOut, "Experimental %s", header.c_str());
|
||||||
|
this->lfAlways(1);
|
||||||
|
fprintf(fOut, "===");
|
||||||
|
}
|
||||||
|
this->markTypeOut(topicDef);
|
||||||
|
}
|
||||||
|
if (fOut) {
|
||||||
|
this->writePending();
|
||||||
|
fclose(fOut);
|
||||||
|
fOut = nullptr;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MdOut::childrenOut(const Definition* def, const char* start) {
|
||||||
|
const char* end;
|
||||||
|
fLineCount = def->fLineCount;
|
||||||
|
if (def->isRoot()) {
|
||||||
|
fRoot = const_cast<RootDefinition*>(def->asRoot());
|
||||||
|
}
|
||||||
|
BmhParser::Resolvable resolvable = this->resolvable(def->fMarkType);
|
||||||
|
for (auto& child : def->fChildren) {
|
||||||
|
end = child->fStart;
|
||||||
|
if (BmhParser::Resolvable::kNo != resolvable) {
|
||||||
|
this->resolveOut(start, end, resolvable);
|
||||||
|
}
|
||||||
|
this->markTypeOut(child);
|
||||||
|
start = child->fTerminator;
|
||||||
|
}
|
||||||
|
if (BmhParser::Resolvable::kNo != resolvable) {
|
||||||
|
end = def->fContentEnd;
|
||||||
|
this->resolveOut(start, end, resolvable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Definition* MdOut::isDefined(const TextParser& parser, const string& ref, bool report) const {
|
||||||
|
auto rootIter = fBmhParser.fClassMap.find(ref);
|
||||||
|
if (rootIter != fBmhParser.fClassMap.end()) {
|
||||||
|
return &rootIter->second;
|
||||||
|
}
|
||||||
|
auto typedefIter = fBmhParser.fTypedefMap.find(ref);
|
||||||
|
if (typedefIter != fBmhParser.fTypedefMap.end()) {
|
||||||
|
return &typedefIter->second;
|
||||||
|
}
|
||||||
|
auto enumIter = fBmhParser.fEnumMap.find(ref);
|
||||||
|
if (enumIter != fBmhParser.fEnumMap.end()) {
|
||||||
|
return &enumIter->second;
|
||||||
|
}
|
||||||
|
auto constIter = fBmhParser.fConstMap.find(ref);
|
||||||
|
if (constIter != fBmhParser.fConstMap.end()) {
|
||||||
|
return &constIter->second;
|
||||||
|
}
|
||||||
|
auto methodIter = fBmhParser.fMethodMap.find(ref);
|
||||||
|
if (methodIter != fBmhParser.fMethodMap.end()) {
|
||||||
|
return &methodIter->second;
|
||||||
|
}
|
||||||
|
auto aliasIter = fBmhParser.fAliasMap.find(ref);
|
||||||
|
if (aliasIter != fBmhParser.fAliasMap.end()) {
|
||||||
|
return aliasIter->second;
|
||||||
|
}
|
||||||
|
for (const auto& external : fBmhParser.fExternals) {
|
||||||
|
if (external.fName == ref) {
|
||||||
|
return &external;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fRoot) {
|
||||||
|
if (ref == fRoot->fName) {
|
||||||
|
return fRoot;
|
||||||
|
}
|
||||||
|
if (const Definition* definition = fRoot->find(ref)) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
Definition* test = fRoot;
|
||||||
|
do {
|
||||||
|
if (!test->isRoot()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RootDefinition* root = test->asRoot();
|
||||||
|
for (auto& leaf : root->fBranches) {
|
||||||
|
if (ref == leaf.first) {
|
||||||
|
return leaf.second;
|
||||||
|
}
|
||||||
|
const Definition* definition = leaf.second->find(ref);
|
||||||
|
if (definition) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (string prefix : { "::", "_" } ) {
|
||||||
|
string prefixed = root->fName + prefix + ref;
|
||||||
|
if (const Definition* definition = root->find(prefixed)) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
if (isupper(prefixed[0])) {
|
||||||
|
auto topicIter = fBmhParser.fTopicMap.find(prefixed);
|
||||||
|
if (topicIter != fBmhParser.fTopicMap.end()) {
|
||||||
|
return topicIter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ((test = test->fParent));
|
||||||
|
}
|
||||||
|
size_t doubleColon = ref.find("::");
|
||||||
|
if (string::npos != doubleColon) {
|
||||||
|
string className = ref.substr(0, doubleColon);
|
||||||
|
auto classIter = fBmhParser.fClassMap.find(className);
|
||||||
|
if (classIter != fBmhParser.fClassMap.end()) {
|
||||||
|
const RootDefinition& classDef = classIter->second;
|
||||||
|
const Definition* result = classDef.find(ref);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!ref.compare(0, 2, "SK") || !ref.compare(0, 3, "sk_")
|
||||||
|
|| (('k' == ref[0] || 'g' == ref[0] || 'f' == ref[0]) &&
|
||||||
|
ref.length() > 1 && isupper(ref[1]))) {
|
||||||
|
// try with a prefix
|
||||||
|
if ('k' == ref[0]) {
|
||||||
|
for (auto const& iter : fBmhParser.fEnumMap) {
|
||||||
|
if (iter.second.find(ref)) {
|
||||||
|
return &iter.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('f' == ref[0]) {
|
||||||
|
// FIXME : find def associated with prior, e.g.: r.fX where 'SkPoint r' was earlier
|
||||||
|
// need to have pushed last resolve on stack to do this
|
||||||
|
// for now, just try to make sure that it's there and error if not
|
||||||
|
if ('.' != parser.backup(ref.c_str())) {
|
||||||
|
parser.reportError("fX member undefined");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (report) {
|
||||||
|
parser.reportError("SK undefined");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isupper(ref[0])) {
|
||||||
|
auto topicIter = fBmhParser.fTopicMap.find(ref);
|
||||||
|
if (topicIter != fBmhParser.fTopicMap.end()) {
|
||||||
|
return topicIter->second;
|
||||||
|
}
|
||||||
|
size_t pos = ref.find('_');
|
||||||
|
if (string::npos != pos) {
|
||||||
|
// see if it is defined by another base class
|
||||||
|
string className(ref, 0, pos);
|
||||||
|
auto classIter = fBmhParser.fClassMap.find(className);
|
||||||
|
if (classIter != fBmhParser.fClassMap.end()) {
|
||||||
|
if (const Definition* definition = classIter->second.find(ref)) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto enumIter = fBmhParser.fEnumMap.find(className);
|
||||||
|
if (enumIter != fBmhParser.fEnumMap.end()) {
|
||||||
|
if (const Definition* definition = enumIter->second.find(ref)) {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (report) {
|
||||||
|
parser.reportError("_ undefined");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
string MdOut::linkName(const Definition* ref) const {
|
||||||
|
string result = ref->fName;
|
||||||
|
size_t under = result.find('_');
|
||||||
|
if (string::npos != under) {
|
||||||
|
string classPart = result.substr(0, under);
|
||||||
|
string namePart = result.substr(under + 1, result.length());
|
||||||
|
if (fRoot && (fRoot->fName == classPart
|
||||||
|
|| (fRoot->fParent && fRoot->fParent->fName == classPart))) {
|
||||||
|
result = namePart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for now, hard-code to html links
|
||||||
|
// def should not include SkXXX_
|
||||||
|
string MdOut::linkRef(const string& leadingSpaces, const Definition* def,
|
||||||
|
const string& ref) const {
|
||||||
|
string buildup;
|
||||||
|
const string* str = &def->fFiddle;
|
||||||
|
SkASSERT(str->length() > 0);
|
||||||
|
size_t under = str->find('_');
|
||||||
|
Definition* curRoot = fRoot;
|
||||||
|
string classPart = string::npos != under ? str->substr(0, under) : *str;
|
||||||
|
bool classMatch = curRoot->fName == classPart;
|
||||||
|
while (curRoot->fParent) {
|
||||||
|
curRoot = curRoot->fParent;
|
||||||
|
classMatch |= curRoot->fName == classPart;
|
||||||
|
}
|
||||||
|
const Definition* defRoot;
|
||||||
|
do {
|
||||||
|
defRoot = def;
|
||||||
|
if (!(def = def->fParent)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
classMatch |= def != defRoot && def->fName == classPart;
|
||||||
|
} while (true);
|
||||||
|
string namePart = string::npos != under ? str->substr(under + 1, str->length()) : *str;
|
||||||
|
SkASSERT(fRoot);
|
||||||
|
SkASSERT(fRoot->fFileName.length());
|
||||||
|
if (false && classMatch) {
|
||||||
|
str = &namePart;
|
||||||
|
} else if (true || (curRoot != defRoot && defRoot->isRoot())) {
|
||||||
|
string filename = defRoot->asRoot()->fFileName;
|
||||||
|
if (filename.substr(filename.length() - 4) == ".bmh") {
|
||||||
|
filename = filename.substr(0, filename.length() - 4);
|
||||||
|
}
|
||||||
|
size_t start = filename.length();
|
||||||
|
while (start > 0 && (isalnum(filename[start - 1]) || '_' == filename[start - 1])) {
|
||||||
|
--start;
|
||||||
|
}
|
||||||
|
buildup = "bmh_" + filename.substr(start) + "?cl=9919#"
|
||||||
|
+ (classMatch ? namePart : *str);
|
||||||
|
str = &buildup;
|
||||||
|
}
|
||||||
|
string refOut(ref);
|
||||||
|
std::replace(refOut.begin(), refOut.end(), '_', ' ');
|
||||||
|
if (ref.length() > 2 && islower(ref[0]) && "()" == ref.substr(ref.length() - 2)) {
|
||||||
|
refOut = refOut.substr(0, refOut.length() - 2);
|
||||||
|
}
|
||||||
|
return leadingSpaces + "<a href=\"" + *str + "\">" + refOut + "</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MdOut::markTypeOut(Definition* def) {
|
||||||
|
string printable = def->printableName();
|
||||||
|
const char* textStart = def->fContentStart;
|
||||||
|
if (MarkType::kParam != def->fMarkType && MarkType::kConst != def->fMarkType &&
|
||||||
|
(!def->fParent || MarkType::kConst != def->fParent->fMarkType) &&
|
||||||
|
TableState::kNone != fTableState) {
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "</table>");
|
||||||
|
this->lf(2);
|
||||||
|
fTableState = TableState::kNone;
|
||||||
|
}
|
||||||
|
switch (def->fMarkType) {
|
||||||
|
case MarkType::kAlias:
|
||||||
|
break;
|
||||||
|
case MarkType::kAnchor:
|
||||||
|
break;
|
||||||
|
case MarkType::kBug:
|
||||||
|
break;
|
||||||
|
case MarkType::kClass:
|
||||||
|
this->mdHeaderOut(1);
|
||||||
|
fprintf(fOut, "<a name=\"%s\"></a> Class %s", this->linkName(def).c_str(),
|
||||||
|
def->fName.c_str());
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kCode:
|
||||||
|
this->lfAlways(2);
|
||||||
|
fprintf(fOut, "<pre style=\"padding: 1em 1em 1em 1em;"
|
||||||
|
"width: 44em; background-color: #f0f0f0\">");
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kColumn:
|
||||||
|
this->writePending();
|
||||||
|
if (fInList) {
|
||||||
|
fprintf(fOut, " <td>");
|
||||||
|
} else {
|
||||||
|
fprintf(fOut, "| ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MarkType::kComment:
|
||||||
|
break;
|
||||||
|
case MarkType::kConst: {
|
||||||
|
if (TableState::kNone == fTableState) {
|
||||||
|
this->mdHeaderOut(3);
|
||||||
|
fprintf(fOut, "Constants\n"
|
||||||
|
"\n"
|
||||||
|
"<table>");
|
||||||
|
fTableState = TableState::kRow;
|
||||||
|
this->lf(1);
|
||||||
|
}
|
||||||
|
if (TableState::kRow == fTableState) {
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, " <tr>");
|
||||||
|
this->lf(1);
|
||||||
|
fTableState = TableState::kColumn;
|
||||||
|
}
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, " <td><a name=\"%s\"></a> <code><strong>%s </strong></code></td>",
|
||||||
|
def->fName.c_str(), def->fName.c_str());
|
||||||
|
const char* lineEnd = strchr(textStart, '\n');
|
||||||
|
SkASSERT(lineEnd < def->fTerminator);
|
||||||
|
SkASSERT(lineEnd > textStart);
|
||||||
|
SkASSERT((int) (lineEnd - textStart) == lineEnd - textStart);
|
||||||
|
fprintf(fOut, "<td>%.*s</td>", (int) (lineEnd - textStart), textStart);
|
||||||
|
fprintf(fOut, "<td>");
|
||||||
|
textStart = lineEnd;
|
||||||
|
} break;
|
||||||
|
case MarkType::kDefine:
|
||||||
|
break;
|
||||||
|
case MarkType::kDefinedBy:
|
||||||
|
break;
|
||||||
|
case MarkType::kDeprecated:
|
||||||
|
break;
|
||||||
|
case MarkType::kDescription:
|
||||||
|
fInDescription = true;
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "<div>");
|
||||||
|
break;
|
||||||
|
case MarkType::kDoxygen:
|
||||||
|
break;
|
||||||
|
case MarkType::kEnum:
|
||||||
|
case MarkType::kEnumClass:
|
||||||
|
this->mdHeaderOut(2);
|
||||||
|
fprintf(fOut, "<a name=\"%s\"></a> Enum %s", def->fName.c_str(), def->fName.c_str());
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kError:
|
||||||
|
break;
|
||||||
|
case MarkType::kExample: {
|
||||||
|
this->mdHeaderOut(3);
|
||||||
|
fprintf(fOut, "Example\n"
|
||||||
|
"\n");
|
||||||
|
fHasFiddle = true;
|
||||||
|
const Definition* platform = def->hasChild(MarkType::kPlatform);
|
||||||
|
if (platform) {
|
||||||
|
TextParser platParse(platform);
|
||||||
|
fHasFiddle = !platParse.strnstr("!fiddle", platParse.fEnd);
|
||||||
|
}
|
||||||
|
if (fHasFiddle) {
|
||||||
|
fprintf(fOut, "<div><fiddle-embed name=\"%s\">", def->fHash.c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(fOut, "<pre style=\"padding: 1em 1em 1em 1em;"
|
||||||
|
"width: 44em; background-color: #f0f0f0\">");
|
||||||
|
this->lf(1);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case MarkType::kExperimental:
|
||||||
|
break;
|
||||||
|
case MarkType::kExternal:
|
||||||
|
break;
|
||||||
|
case MarkType::kFile:
|
||||||
|
break;
|
||||||
|
case MarkType::kFormula:
|
||||||
|
break;
|
||||||
|
case MarkType::kFunction:
|
||||||
|
break;
|
||||||
|
case MarkType::kHeight:
|
||||||
|
break;
|
||||||
|
case MarkType::kImage:
|
||||||
|
break;
|
||||||
|
case MarkType::kLegend:
|
||||||
|
break;
|
||||||
|
case MarkType::kLink:
|
||||||
|
break;
|
||||||
|
case MarkType::kList:
|
||||||
|
fInList = true;
|
||||||
|
this->lfAlways(2);
|
||||||
|
fprintf(fOut, "<table>");
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kMarkChar:
|
||||||
|
fBmhParser.fMC = def->fContentStart[0];
|
||||||
|
break;
|
||||||
|
case MarkType::kMember: {
|
||||||
|
TextParser tp(def->fFileName, def->fStart, def->fContentStart, def->fLineCount);
|
||||||
|
tp.skipExact("#Member");
|
||||||
|
tp.skipWhiteSpace();
|
||||||
|
const char* end = tp.trimmedBracketEnd('\n', TextParser::OneLine::kYes);
|
||||||
|
this->lfAlways(2);
|
||||||
|
fprintf(fOut, "<code><strong>%.*s</strong></code>", (int) (end - tp.fChar), tp.fChar);
|
||||||
|
this->lf(2);
|
||||||
|
} break;
|
||||||
|
case MarkType::kMethod: {
|
||||||
|
string method_name = def->methodName();
|
||||||
|
string formattedStr = def->formatFunction();
|
||||||
|
|
||||||
|
if (!def->isClone()) {
|
||||||
|
this->lfAlways(2);
|
||||||
|
fprintf(fOut, "<a name=\"%s\"></a>", def->fiddleName().c_str());
|
||||||
|
this->mdHeaderOutLF(2, 1);
|
||||||
|
fprintf(fOut, "%s", method_name.c_str());
|
||||||
|
this->lf(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: put in css spec that we can define somewhere else (if markup supports that)
|
||||||
|
// TODO: 50em below should match limt = 80 in formatFunction()
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "<pre style=\"padding: 1em 1em 1em 1em;"
|
||||||
|
"width: 50em; background-color: #f0f0f0\">\n"
|
||||||
|
"%s\n"
|
||||||
|
"</pre>", formattedStr.c_str());
|
||||||
|
this->lf(2);
|
||||||
|
fTableState = TableState::kNone;
|
||||||
|
fMethod = def;
|
||||||
|
} break;
|
||||||
|
case MarkType::kNoExample:
|
||||||
|
break;
|
||||||
|
case MarkType::kParam: {
|
||||||
|
if (TableState::kNone == fTableState) {
|
||||||
|
this->mdHeaderOut(3);
|
||||||
|
fprintf(fOut,
|
||||||
|
"Parameters\n"
|
||||||
|
"\n"
|
||||||
|
"<table>"
|
||||||
|
);
|
||||||
|
this->lf(1);
|
||||||
|
fTableState = TableState::kRow;
|
||||||
|
}
|
||||||
|
if (TableState::kRow == fTableState) {
|
||||||
|
fprintf(fOut, " <tr>");
|
||||||
|
this->lf(1);
|
||||||
|
fTableState = TableState::kColumn;
|
||||||
|
}
|
||||||
|
TextParser paramParser(def->fFileName, def->fStart, def->fContentStart,
|
||||||
|
def->fLineCount);
|
||||||
|
paramParser.skipWhiteSpace();
|
||||||
|
SkASSERT(paramParser.startsWith("#Param"));
|
||||||
|
paramParser.next(); // skip hash
|
||||||
|
paramParser.skipToNonAlphaNum(); // skip Param
|
||||||
|
paramParser.skipSpace();
|
||||||
|
const char* paramName = paramParser.fChar;
|
||||||
|
paramParser.skipToSpace();
|
||||||
|
fprintf(fOut,
|
||||||
|
" <td><code><strong>%.*s </strong></code></td> <td>",
|
||||||
|
(int) (paramParser.fChar - paramName), paramName);
|
||||||
|
} break;
|
||||||
|
case MarkType::kPlatform:
|
||||||
|
break;
|
||||||
|
case MarkType::kPrivate:
|
||||||
|
break;
|
||||||
|
case MarkType::kReturn:
|
||||||
|
this->mdHeaderOut(3);
|
||||||
|
fprintf(fOut, "Return Value");
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kRow:
|
||||||
|
if (fInList) {
|
||||||
|
fprintf(fOut, " <tr>");
|
||||||
|
this->lf(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MarkType::kSeeAlso:
|
||||||
|
this->mdHeaderOut(3);
|
||||||
|
fprintf(fOut, "See Also");
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kStdOut: {
|
||||||
|
TextParser code(def);
|
||||||
|
this->mdHeaderOut(4);
|
||||||
|
fprintf(fOut,
|
||||||
|
"Example Output\n"
|
||||||
|
"\n"
|
||||||
|
"~~~~");
|
||||||
|
this->lfAlways(1);
|
||||||
|
code.skipSpace();
|
||||||
|
while (!code.eof()) {
|
||||||
|
const char* end = code.trimmedLineEnd();
|
||||||
|
fprintf(fOut, "%.*s\n", (int) (end - code.fChar), code.fChar);
|
||||||
|
code.skipToLineStart();
|
||||||
|
}
|
||||||
|
fprintf(fOut, "~~~~");
|
||||||
|
this->lf(2);
|
||||||
|
} break;
|
||||||
|
case MarkType::kStruct:
|
||||||
|
fRoot = def->asRoot();
|
||||||
|
this->mdHeaderOut(1);
|
||||||
|
fprintf(fOut, "<a name=\"%s\"></a> Struct %s", def->fName.c_str(), def->fName.c_str());
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kSubstitute:
|
||||||
|
break;
|
||||||
|
case MarkType::kSubtopic:
|
||||||
|
this->mdHeaderOut(2);
|
||||||
|
fprintf(fOut, "<a name=\"%s\"></a> %s", def->fName.c_str(), printable.c_str());
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kTable:
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kTemplate:
|
||||||
|
break;
|
||||||
|
case MarkType::kText:
|
||||||
|
break;
|
||||||
|
case MarkType::kTime:
|
||||||
|
break;
|
||||||
|
case MarkType::kToDo:
|
||||||
|
break;
|
||||||
|
case MarkType::kTopic:
|
||||||
|
this->mdHeaderOut(1);
|
||||||
|
fprintf(fOut, "<a name=\"%s\"></a> %s", this->linkName(def).c_str(),
|
||||||
|
printable.c_str());
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kTrack:
|
||||||
|
// don't output children
|
||||||
|
return;
|
||||||
|
case MarkType::kTypedef:
|
||||||
|
break;
|
||||||
|
case MarkType::kUnion:
|
||||||
|
break;
|
||||||
|
case MarkType::kVolatile:
|
||||||
|
break;
|
||||||
|
case MarkType::kWidth:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SkDebugf("fatal error: MarkType::k%s unhandled in %s()\n",
|
||||||
|
fBmhParser.fMaps[(int) def->fMarkType].fName, __func__);
|
||||||
|
SkASSERT(0); // handle everything
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->childrenOut(def, textStart);
|
||||||
|
switch (def->fMarkType) { // post child work, at least for tables
|
||||||
|
case MarkType::kCode:
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "</pre>");
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kColumn:
|
||||||
|
if (fInList) {
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "</td>");
|
||||||
|
this->lf(1);
|
||||||
|
} else {
|
||||||
|
fprintf(fOut, " ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MarkType::kDescription:
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "</div>");
|
||||||
|
fInDescription = false;
|
||||||
|
break;
|
||||||
|
case MarkType::kEnum:
|
||||||
|
case MarkType::kEnumClass:
|
||||||
|
this->lfAlways(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kExample:
|
||||||
|
this->writePending();
|
||||||
|
if (fHasFiddle) {
|
||||||
|
fprintf(fOut, "</fiddle-embed></div>");
|
||||||
|
} else {
|
||||||
|
fprintf(fOut, "</pre>");
|
||||||
|
}
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kList:
|
||||||
|
fInList = false;
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "</table>");
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kLegend: {
|
||||||
|
SkASSERT(def->fChildren.size() == 1);
|
||||||
|
const Definition* row = def->fChildren[0];
|
||||||
|
SkASSERT(MarkType::kRow == row->fMarkType);
|
||||||
|
size_t columnCount = row->fChildren.size();
|
||||||
|
SkASSERT(columnCount > 0);
|
||||||
|
this->writePending();
|
||||||
|
for (size_t index = 0; index < columnCount; ++index) {
|
||||||
|
fprintf(fOut, "| --- ");
|
||||||
|
}
|
||||||
|
fprintf(fOut, " |");
|
||||||
|
this->lf(1);
|
||||||
|
} break;
|
||||||
|
case MarkType::kMethod:
|
||||||
|
fMethod = nullptr;
|
||||||
|
this->lfAlways(2);
|
||||||
|
fprintf(fOut, "---");
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kConst:
|
||||||
|
case MarkType::kParam:
|
||||||
|
SkASSERT(TableState::kColumn == fTableState);
|
||||||
|
fTableState = TableState::kRow;
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "</td>\n");
|
||||||
|
fprintf(fOut, " </tr>");
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kReturn:
|
||||||
|
case MarkType::kSeeAlso:
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kRow:
|
||||||
|
if (fInList) {
|
||||||
|
fprintf(fOut, " </tr>");
|
||||||
|
} else {
|
||||||
|
fprintf(fOut, "|");
|
||||||
|
}
|
||||||
|
this->lf(1);
|
||||||
|
break;
|
||||||
|
case MarkType::kStruct:
|
||||||
|
fRoot = fRoot->rootParent();
|
||||||
|
break;
|
||||||
|
case MarkType::kTable:
|
||||||
|
this->lf(2);
|
||||||
|
break;
|
||||||
|
case MarkType::kPrivate:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MdOut::mdHeaderOutLF(int depth, int lf) {
|
||||||
|
this->lfAlways(lf);
|
||||||
|
for (int index = 0; index < depth; ++index) {
|
||||||
|
fprintf(fOut, "#");
|
||||||
|
}
|
||||||
|
fprintf(fOut, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MdOut::resolveOut(const char* start, const char* end, BmhParser::Resolvable resolvable) {
|
||||||
|
// FIXME: this needs the markdown character present when the def was defined,
|
||||||
|
// not the last markdown character the parser would have seen...
|
||||||
|
while (fBmhParser.fMC == end[-1]) {
|
||||||
|
--end;
|
||||||
|
}
|
||||||
|
if (start >= end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string resolved = this->addReferences(start, end, resolvable);
|
||||||
|
trim_end_spaces(resolved);
|
||||||
|
if (resolved.length()) {
|
||||||
|
TextParser paragraph(fFileName, &*resolved.begin(), &*resolved.end(), fLineCount);
|
||||||
|
TextParser original(fFileName, start, end, fLineCount);
|
||||||
|
while (!original.eof() && '\n' == original.peek()) {
|
||||||
|
original.next();
|
||||||
|
}
|
||||||
|
original.skipSpace();
|
||||||
|
while (!paragraph.eof()) {
|
||||||
|
paragraph.skipWhiteSpace();
|
||||||
|
const char* contentStart = paragraph.fChar;
|
||||||
|
paragraph.skipToEndBracket('\n');
|
||||||
|
ptrdiff_t lineLength = paragraph.fChar - contentStart;
|
||||||
|
if (lineLength) {
|
||||||
|
this->writePending();
|
||||||
|
fprintf(fOut, "%.*s", (int) lineLength, contentStart);
|
||||||
|
}
|
||||||
|
int linefeeds = 0;
|
||||||
|
while (lineLength > 0 && '\n' == contentStart[--lineLength]) {
|
||||||
|
++linefeeds;
|
||||||
|
}
|
||||||
|
if (lineLength > 0) {
|
||||||
|
this->nl();
|
||||||
|
}
|
||||||
|
fLinefeeds += linefeeds;
|
||||||
|
if (paragraph.eof()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ('\n' == paragraph.next()) {
|
||||||
|
linefeeds = 1;
|
||||||
|
if (!paragraph.eof() && '\n' == paragraph.peek()) {
|
||||||
|
linefeeds = 2;
|
||||||
|
}
|
||||||
|
this->lf(linefeeds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
while (end > start && end[0] == '\n') {
|
||||||
|
fprintf(fOut, "\n");
|
||||||
|
--end;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
51
tools/bookmaker/parserCommon.cpp
Normal file
51
tools/bookmaker/parserCommon.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bookmaker.h"
|
||||||
|
|
||||||
|
bool ParserCommon::parseSetup(const char* path) {
|
||||||
|
this->reset();
|
||||||
|
sk_sp<SkData> data = SkData::MakeFromFileName(path);
|
||||||
|
if (nullptr == data.get()) {
|
||||||
|
SkDebugf("%s missing\n", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char* rawText = (const char*) data->data();
|
||||||
|
bool hasCR = false;
|
||||||
|
size_t dataSize = data->size();
|
||||||
|
for (size_t index = 0; index < dataSize; ++index) {
|
||||||
|
if ('\r' == rawText[index]) {
|
||||||
|
hasCR = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string name(path);
|
||||||
|
if (hasCR) {
|
||||||
|
vector<char> lfOnly;
|
||||||
|
for (size_t index = 0; index < dataSize; ++index) {
|
||||||
|
char ch = rawText[index];
|
||||||
|
if ('\r' == rawText[index]) {
|
||||||
|
ch = '\n';
|
||||||
|
if ('\n' == rawText[index + 1]) {
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lfOnly.push_back(ch);
|
||||||
|
}
|
||||||
|
fLFOnly[name] = lfOnly;
|
||||||
|
dataSize = lfOnly.size();
|
||||||
|
rawText = &fLFOnly[name].front();
|
||||||
|
}
|
||||||
|
fRawData[name] = data;
|
||||||
|
fStart = rawText;
|
||||||
|
fLine = rawText;
|
||||||
|
fChar = rawText;
|
||||||
|
fEnd = rawText + dataSize;
|
||||||
|
fFileName = string(path);
|
||||||
|
fLineCount = 1;
|
||||||
|
return true;
|
||||||
|
}
|
455
tools/bookmaker/spellCheck.cpp
Normal file
455
tools/bookmaker/spellCheck.cpp
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bookmaker.h"
|
||||||
|
|
||||||
|
#include "SkOSFile.h"
|
||||||
|
#include "SkOSPath.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
things to do
|
||||||
|
if cap word is beginning of sentence, add it to table as lower-case
|
||||||
|
word must have only a single initial capital
|
||||||
|
|
||||||
|
if word is camel cased, look for :: matches on suffix
|
||||||
|
|
||||||
|
when function crosses lines, whole thing isn't seen as a 'word' e.g., search for largeArc in path
|
||||||
|
|
||||||
|
words in external not seen
|
||||||
|
*/
|
||||||
|
struct CheckEntry {
|
||||||
|
string fFile;
|
||||||
|
int fLine;
|
||||||
|
int fCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpellCheck : public ParserCommon {
|
||||||
|
public:
|
||||||
|
SpellCheck(const BmhParser& bmh) : ParserCommon()
|
||||||
|
, fBmhParser(bmh) {
|
||||||
|
this->reset();
|
||||||
|
}
|
||||||
|
bool check(const char* match);
|
||||||
|
void report();
|
||||||
|
private:
|
||||||
|
enum class TableState {
|
||||||
|
kNone,
|
||||||
|
kRow,
|
||||||
|
kColumn,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool check(Definition* );
|
||||||
|
bool checkable(MarkType markType);
|
||||||
|
void childCheck(const Definition* def, const char* start);
|
||||||
|
void leafCheck(const char* start, const char* end);
|
||||||
|
bool parseFromFile(const char* path) override { return true; }
|
||||||
|
void printCheck(const string& str);
|
||||||
|
|
||||||
|
void reset() override {
|
||||||
|
INHERITED::resetCommon();
|
||||||
|
fMethod = nullptr;
|
||||||
|
fRoot = nullptr;
|
||||||
|
fTableState = TableState::kNone;
|
||||||
|
fInCode = false;
|
||||||
|
fInConst = false;
|
||||||
|
fInDescription = false;
|
||||||
|
fInStdOut = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wordCheck(const string& str);
|
||||||
|
void wordCheck(ptrdiff_t len, const char* ch);
|
||||||
|
|
||||||
|
unordered_map<string, CheckEntry> fCode;
|
||||||
|
unordered_map<string, CheckEntry> fColons;
|
||||||
|
unordered_map<string, CheckEntry> fDigits;
|
||||||
|
unordered_map<string, CheckEntry> fDots;
|
||||||
|
unordered_map<string, CheckEntry> fParens; // also hold destructors, operators
|
||||||
|
unordered_map<string, CheckEntry> fUnderscores;
|
||||||
|
unordered_map<string, CheckEntry> fWords;
|
||||||
|
const BmhParser& fBmhParser;
|
||||||
|
Definition* fMethod;
|
||||||
|
RootDefinition* fRoot;
|
||||||
|
TableState fTableState;
|
||||||
|
bool fInCode;
|
||||||
|
bool fInConst;
|
||||||
|
bool fInDescription;
|
||||||
|
bool fInStdOut;
|
||||||
|
typedef ParserCommon INHERITED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This doesn't perform a traditional spell or grammar check, although
|
||||||
|
maybe it should. Instead it looks for words used uncommonly and lower
|
||||||
|
case words that match capitalized words that are not sentence starters.
|
||||||
|
It also looks for articles preceeding capitalized words and their
|
||||||
|
modifiers to try to maintain a consistent voice.
|
||||||
|
Maybe also look for passive verbs (e.g. 'is') and suggest active ones?
|
||||||
|
*/
|
||||||
|
void BmhParser::spellCheck(const char* match) const {
|
||||||
|
SpellCheck checker(*this);
|
||||||
|
checker.check(match);
|
||||||
|
checker.report();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpellCheck::check(const char* match) {
|
||||||
|
for (const auto& topic : fBmhParser.fTopicMap) {
|
||||||
|
Definition* topicDef = topic.second;
|
||||||
|
if (topicDef->fParent) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!topicDef->isRoot()) {
|
||||||
|
return this->reportError<bool>("expected root topic");
|
||||||
|
}
|
||||||
|
fRoot = topicDef->asRoot();
|
||||||
|
if (string::npos == fRoot->fFileName.rfind(match)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this->check(topicDef);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpellCheck::check(Definition* def) {
|
||||||
|
fFileName = def->fFileName;
|
||||||
|
fLineCount = def->fLineCount;
|
||||||
|
string printable = def->printableName();
|
||||||
|
const char* textStart = def->fContentStart;
|
||||||
|
if (MarkType::kParam != def->fMarkType && MarkType::kConst != def->fMarkType &&
|
||||||
|
TableState::kNone != fTableState) {
|
||||||
|
fTableState = TableState::kNone;
|
||||||
|
}
|
||||||
|
switch (def->fMarkType) {
|
||||||
|
case MarkType::kAlias:
|
||||||
|
break;
|
||||||
|
case MarkType::kAnchor:
|
||||||
|
break;
|
||||||
|
case MarkType::kBug:
|
||||||
|
break;
|
||||||
|
case MarkType::kClass:
|
||||||
|
this->wordCheck(def->fName);
|
||||||
|
break;
|
||||||
|
case MarkType::kCode:
|
||||||
|
fInCode = true;
|
||||||
|
break;
|
||||||
|
case MarkType::kColumn:
|
||||||
|
break;
|
||||||
|
case MarkType::kComment:
|
||||||
|
break;
|
||||||
|
case MarkType::kConst: {
|
||||||
|
fInConst = true;
|
||||||
|
if (TableState::kNone == fTableState) {
|
||||||
|
fTableState = TableState::kRow;
|
||||||
|
}
|
||||||
|
if (TableState::kRow == fTableState) {
|
||||||
|
fTableState = TableState::kColumn;
|
||||||
|
}
|
||||||
|
this->wordCheck(def->fName);
|
||||||
|
const char* lineEnd = strchr(textStart, '\n');
|
||||||
|
this->wordCheck(lineEnd - textStart, textStart);
|
||||||
|
textStart = lineEnd;
|
||||||
|
} break;
|
||||||
|
case MarkType::kDefine:
|
||||||
|
break;
|
||||||
|
case MarkType::kDefinedBy:
|
||||||
|
break;
|
||||||
|
case MarkType::kDeprecated:
|
||||||
|
break;
|
||||||
|
case MarkType::kDescription:
|
||||||
|
fInDescription = true;
|
||||||
|
break;
|
||||||
|
case MarkType::kDoxygen:
|
||||||
|
break;
|
||||||
|
case MarkType::kEnum:
|
||||||
|
case MarkType::kEnumClass:
|
||||||
|
this->wordCheck(def->fName);
|
||||||
|
break;
|
||||||
|
case MarkType::kError:
|
||||||
|
break;
|
||||||
|
case MarkType::kExample:
|
||||||
|
break;
|
||||||
|
case MarkType::kExternal:
|
||||||
|
break;
|
||||||
|
case MarkType::kFile:
|
||||||
|
break;
|
||||||
|
case MarkType::kFormula:
|
||||||
|
break;
|
||||||
|
case MarkType::kFunction:
|
||||||
|
break;
|
||||||
|
case MarkType::kHeight:
|
||||||
|
break;
|
||||||
|
case MarkType::kImage:
|
||||||
|
break;
|
||||||
|
case MarkType::kLegend:
|
||||||
|
break;
|
||||||
|
case MarkType::kList:
|
||||||
|
break;
|
||||||
|
case MarkType::kMember:
|
||||||
|
break;
|
||||||
|
case MarkType::kMethod: {
|
||||||
|
string method_name = def->methodName();
|
||||||
|
string formattedStr = def->formatFunction();
|
||||||
|
if (!def->isClone()) {
|
||||||
|
this->wordCheck(method_name);
|
||||||
|
}
|
||||||
|
fTableState = TableState::kNone;
|
||||||
|
fMethod = def;
|
||||||
|
} break;
|
||||||
|
case MarkType::kParam: {
|
||||||
|
if (TableState::kNone == fTableState) {
|
||||||
|
fTableState = TableState::kRow;
|
||||||
|
}
|
||||||
|
if (TableState::kRow == fTableState) {
|
||||||
|
fTableState = TableState::kColumn;
|
||||||
|
}
|
||||||
|
TextParser paramParser(def->fFileName, def->fStart, def->fContentStart,
|
||||||
|
def->fLineCount);
|
||||||
|
paramParser.skipWhiteSpace();
|
||||||
|
SkASSERT(paramParser.startsWith("#Param"));
|
||||||
|
paramParser.next(); // skip hash
|
||||||
|
paramParser.skipToNonAlphaNum(); // skip Param
|
||||||
|
paramParser.skipSpace();
|
||||||
|
const char* paramName = paramParser.fChar;
|
||||||
|
paramParser.skipToSpace();
|
||||||
|
fInCode = true;
|
||||||
|
this->wordCheck(paramParser.fChar - paramName, paramName);
|
||||||
|
fInCode = false;
|
||||||
|
} break;
|
||||||
|
case MarkType::kPlatform:
|
||||||
|
break;
|
||||||
|
case MarkType::kReturn:
|
||||||
|
break;
|
||||||
|
case MarkType::kRow:
|
||||||
|
break;
|
||||||
|
case MarkType::kSeeAlso:
|
||||||
|
break;
|
||||||
|
case MarkType::kStdOut: {
|
||||||
|
fInStdOut = true;
|
||||||
|
TextParser code(def);
|
||||||
|
code.skipSpace();
|
||||||
|
while (!code.eof()) {
|
||||||
|
const char* end = code.trimmedLineEnd();
|
||||||
|
this->wordCheck(end - code.fChar, code.fChar);
|
||||||
|
code.skipToLineStart();
|
||||||
|
}
|
||||||
|
fInStdOut = false;
|
||||||
|
} break;
|
||||||
|
case MarkType::kStruct:
|
||||||
|
fRoot = def->asRoot();
|
||||||
|
this->wordCheck(def->fName);
|
||||||
|
break;
|
||||||
|
case MarkType::kSubtopic:
|
||||||
|
this->printCheck(printable);
|
||||||
|
break;
|
||||||
|
case MarkType::kTable:
|
||||||
|
break;
|
||||||
|
case MarkType::kTemplate:
|
||||||
|
break;
|
||||||
|
case MarkType::kText:
|
||||||
|
break;
|
||||||
|
case MarkType::kTime:
|
||||||
|
break;
|
||||||
|
case MarkType::kToDo:
|
||||||
|
break;
|
||||||
|
case MarkType::kTopic:
|
||||||
|
this->printCheck(printable);
|
||||||
|
break;
|
||||||
|
case MarkType::kTrack:
|
||||||
|
// don't output children
|
||||||
|
return true;
|
||||||
|
case MarkType::kTypedef:
|
||||||
|
break;
|
||||||
|
case MarkType::kUnion:
|
||||||
|
break;
|
||||||
|
case MarkType::kWidth:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SkASSERT(0); // handle everything
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->childCheck(def, textStart);
|
||||||
|
switch (def->fMarkType) { // post child work, at least for tables
|
||||||
|
case MarkType::kCode:
|
||||||
|
fInCode = false;
|
||||||
|
break;
|
||||||
|
case MarkType::kColumn:
|
||||||
|
break;
|
||||||
|
case MarkType::kDescription:
|
||||||
|
fInDescription = false;
|
||||||
|
break;
|
||||||
|
case MarkType::kEnum:
|
||||||
|
case MarkType::kEnumClass:
|
||||||
|
break;
|
||||||
|
case MarkType::kExample:
|
||||||
|
break;
|
||||||
|
case MarkType::kLegend:
|
||||||
|
break;
|
||||||
|
case MarkType::kMethod:
|
||||||
|
fMethod = nullptr;
|
||||||
|
break;
|
||||||
|
case MarkType::kConst:
|
||||||
|
fInConst = false;
|
||||||
|
case MarkType::kParam:
|
||||||
|
SkASSERT(TableState::kColumn == fTableState);
|
||||||
|
fTableState = TableState::kRow;
|
||||||
|
break;
|
||||||
|
case MarkType::kReturn:
|
||||||
|
case MarkType::kSeeAlso:
|
||||||
|
break;
|
||||||
|
case MarkType::kRow:
|
||||||
|
break;
|
||||||
|
case MarkType::kStruct:
|
||||||
|
fRoot = fRoot->rootParent();
|
||||||
|
break;
|
||||||
|
case MarkType::kTable:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpellCheck::checkable(MarkType markType) {
|
||||||
|
return BmhParser::Resolvable::kYes == fBmhParser.fMaps[(int) markType].fResolve;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCheck::childCheck(const Definition* def, const char* start) {
|
||||||
|
const char* end;
|
||||||
|
fLineCount = def->fLineCount;
|
||||||
|
if (def->isRoot()) {
|
||||||
|
fRoot = const_cast<RootDefinition*>(def->asRoot());
|
||||||
|
}
|
||||||
|
for (auto& child : def->fChildren) {
|
||||||
|
end = child->fStart;
|
||||||
|
if (this->checkable(def->fMarkType)) {
|
||||||
|
this->leafCheck(start, end);
|
||||||
|
}
|
||||||
|
this->check(child);
|
||||||
|
start = child->fTerminator;
|
||||||
|
}
|
||||||
|
if (this->checkable(def->fMarkType)) {
|
||||||
|
end = def->fContentEnd;
|
||||||
|
this->leafCheck(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCheck::leafCheck(const char* start, const char* end) {
|
||||||
|
TextParser text("", start, end, fLineCount);
|
||||||
|
do {
|
||||||
|
const char* lineStart = text.fChar;
|
||||||
|
text.skipToAlpha();
|
||||||
|
if (text.eof()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char* wordStart = text.fChar;
|
||||||
|
text.fChar = lineStart;
|
||||||
|
text.skipTo(wordStart); // advances line number
|
||||||
|
text.skipToNonAlphaNum();
|
||||||
|
fLineCount = text.fLineCount;
|
||||||
|
string word(wordStart, text.fChar - wordStart);
|
||||||
|
wordCheck(word);
|
||||||
|
} while (!text.eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCheck::printCheck(const string& str) {
|
||||||
|
string word;
|
||||||
|
for (std::stringstream stream(str); stream >> word; ) {
|
||||||
|
wordCheck(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCheck::report() {
|
||||||
|
for (auto iter : fWords) {
|
||||||
|
if (string::npos != iter.second.fFile.find("undocumented.bmh")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (string::npos != iter.second.fFile.find("markup.bmh")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (string::npos != iter.second.fFile.find("usingBookmaker.bmh")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (iter.second.fCount == 1) {
|
||||||
|
SkDebugf("%s %s %d\n", iter.first.c_str(), iter.second.fFile.c_str(),
|
||||||
|
iter.second.fLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCheck::wordCheck(const string& str) {
|
||||||
|
bool hasColon = false;
|
||||||
|
bool hasDot = false;
|
||||||
|
bool hasParen = false;
|
||||||
|
bool hasUnderscore = false;
|
||||||
|
bool sawDash = false;
|
||||||
|
bool sawDigit = false;
|
||||||
|
bool sawSpecial = false;
|
||||||
|
SkASSERT(str.length() > 0);
|
||||||
|
SkASSERT(isalpha(str[0]) || '~' == str[0]);
|
||||||
|
for (char ch : str) {
|
||||||
|
if (isalpha(ch) || '-' == ch) {
|
||||||
|
sawDash |= '-' == ch;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool isColon = ':' == ch;
|
||||||
|
hasColon |= isColon;
|
||||||
|
bool isDot = '.' == ch;
|
||||||
|
hasDot |= isDot;
|
||||||
|
bool isParen = '(' == ch || ')' == ch || '~' == ch || '=' == ch || '!' == ch;
|
||||||
|
hasParen |= isParen;
|
||||||
|
bool isUnderscore = '_' == ch;
|
||||||
|
hasUnderscore |= isUnderscore;
|
||||||
|
if (isColon || isDot || isUnderscore || isParen) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isdigit(ch)) {
|
||||||
|
sawDigit = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('&' == ch || ',' == ch || ' ' == ch) {
|
||||||
|
sawSpecial = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SkASSERT(0);
|
||||||
|
}
|
||||||
|
if (sawSpecial && !hasParen) {
|
||||||
|
SkASSERT(0);
|
||||||
|
}
|
||||||
|
bool inCode = fInCode;
|
||||||
|
if (hasUnderscore && isupper(str[0]) && ('S' != str[0] || 'K' != str[1])
|
||||||
|
&& !hasColon && !hasDot && !hasParen && !fInStdOut && !inCode && !fInConst
|
||||||
|
&& !sawDigit && !sawSpecial && !sawDash) {
|
||||||
|
std::istringstream ss(str);
|
||||||
|
string token;
|
||||||
|
while (std::getline(ss, token, '_')) {
|
||||||
|
this->wordCheck(token);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!hasColon && !hasDot && !hasParen && !hasUnderscore
|
||||||
|
&& !fInStdOut && !inCode && !fInConst && !sawDigit
|
||||||
|
&& islower(str[0]) && isupper(str[1])) {
|
||||||
|
inCode = true;
|
||||||
|
}
|
||||||
|
auto& mappy = hasColon ? fColons :
|
||||||
|
hasDot ? fDots :
|
||||||
|
hasParen ? fParens :
|
||||||
|
hasUnderscore ? fUnderscores :
|
||||||
|
fInStdOut || inCode || fInConst ? fCode :
|
||||||
|
sawDigit ? fDigits : fWords;
|
||||||
|
auto iter = mappy.find(str);
|
||||||
|
if (mappy.end() != iter) {
|
||||||
|
iter->second.fCount += 1;
|
||||||
|
} else {
|
||||||
|
CheckEntry* entry = &mappy[str];
|
||||||
|
entry->fFile = fFileName;
|
||||||
|
entry->fLine = fLineCount;
|
||||||
|
entry->fCount = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCheck::wordCheck(ptrdiff_t len, const char* ch) {
|
||||||
|
leafCheck(ch, ch + len);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user