2021-10-15 05:39:56 -04:00
|
|
|
import {
|
2024-01-26 04:23:48 -05:00
|
|
|
FC,
|
2021-10-15 05:39:56 -04:00
|
|
|
createContext,
|
|
|
|
useCallback,
|
|
|
|
useContext,
|
|
|
|
useEffect,
|
|
|
|
useMemo,
|
2022-03-03 11:28:12 -05:00
|
|
|
useRef,
|
2021-10-15 05:39:56 -04:00
|
|
|
useState,
|
|
|
|
} from 'react'
|
2021-10-08 06:09:41 -04:00
|
|
|
import useScopeValue from '../hooks/use-scope-value'
|
2021-11-03 10:30:41 -04:00
|
|
|
import useScopeValueSetterOnly from '../hooks/use-scope-value-setter-only'
|
2021-10-15 05:39:56 -04:00
|
|
|
import usePersistedState from '../hooks/use-persisted-state'
|
|
|
|
import useAbortController from '../hooks/use-abort-controller'
|
|
|
|
import DocumentCompiler from '../../features/pdf-preview/util/compiler'
|
2022-03-31 07:22:36 -04:00
|
|
|
import {
|
|
|
|
send,
|
2024-01-23 08:00:09 -05:00
|
|
|
sendMB,
|
2022-03-31 07:22:36 -04:00
|
|
|
sendMBOnce,
|
|
|
|
sendMBSampled,
|
|
|
|
} from '../../infrastructure/event-tracking'
|
2021-10-15 05:39:56 -04:00
|
|
|
import {
|
|
|
|
buildLogEntryAnnotations,
|
2024-02-05 06:41:49 -05:00
|
|
|
buildRuleCounts,
|
2022-03-25 05:42:10 -04:00
|
|
|
handleLogFiles,
|
2021-10-15 05:39:56 -04:00
|
|
|
handleOutputFiles,
|
|
|
|
} from '../../features/pdf-preview/util/output-files'
|
|
|
|
import { useIdeContext } from './ide-context'
|
|
|
|
import { useProjectContext } from './project-context'
|
|
|
|
import { useEditorContext } from './editor-context'
|
2022-03-25 05:42:10 -04:00
|
|
|
import { buildFileList } from '../../features/pdf-preview/util/file-list'
|
2022-07-21 04:31:31 -04:00
|
|
|
import { useLayoutContext } from './layout-context'
|
2022-12-20 08:01:54 -05:00
|
|
|
import { useUserContext } from './user-context'
|
2023-10-26 06:01:08 -04:00
|
|
|
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
|
|
|
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
2023-11-21 09:29:44 -05:00
|
|
|
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
2024-01-23 08:00:09 -05:00
|
|
|
import { useSplitTestContext } from '@/shared/context/split-test-context'
|
2022-07-13 04:33:47 -04:00
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
type PdfFile = Record<string, any>
|
|
|
|
|
|
|
|
export type CompileContext = {
|
|
|
|
autoCompile: boolean
|
|
|
|
clearingCache: boolean
|
|
|
|
clsiServerId?: string
|
|
|
|
codeCheckFailed: boolean
|
|
|
|
compiling: boolean
|
|
|
|
deliveryLatencies: Record<string, any>
|
|
|
|
draft: boolean
|
|
|
|
error?: string
|
|
|
|
fileList?: Record<string, any>
|
|
|
|
hasChanges: boolean
|
|
|
|
highlights?: Record<string, any>[]
|
|
|
|
isProjectOwner: boolean
|
|
|
|
logEntries?: Record<string, any>
|
|
|
|
logEntryAnnotations?: Record<string, any>
|
|
|
|
pdfDownloadUrl?: string
|
|
|
|
pdfFile?: PdfFile
|
|
|
|
pdfUrl?: string
|
|
|
|
pdfViewer?: string
|
|
|
|
position?: Record<string, any>
|
|
|
|
rawLog?: string
|
|
|
|
setAutoCompile: (value: boolean) => void
|
|
|
|
setDraft: (value: any) => void
|
|
|
|
setError: (value: any) => void
|
|
|
|
setHasLintingError: (value: any) => void // only for storybook
|
|
|
|
setHighlights: (value: any) => void
|
|
|
|
setPosition: (value: any) => void
|
|
|
|
setShowCompileTimeWarning: (value: any) => void
|
|
|
|
setShowLogs: (value: boolean) => void
|
|
|
|
toggleLogs: () => void
|
|
|
|
setStopOnFirstError: (value: boolean) => void
|
|
|
|
setStopOnValidationError: (value: boolean) => void
|
|
|
|
showCompileTimeWarning: boolean
|
|
|
|
showLogs: boolean
|
|
|
|
showNewCompileTimeoutUI?: string
|
|
|
|
showFasterCompilesFeedbackUI: boolean
|
|
|
|
stopOnFirstError: boolean
|
|
|
|
stopOnValidationError: boolean
|
|
|
|
stoppedOnFirstError: boolean
|
|
|
|
uncompiled?: boolean
|
|
|
|
validationIssues?: Record<string, any>
|
|
|
|
firstRenderDone: () => void
|
|
|
|
cleanupCompileResult?: () => void
|
|
|
|
animateCompileDropdownArrow: boolean
|
|
|
|
editedSinceCompileStarted: boolean
|
|
|
|
lastCompileOptions: any
|
|
|
|
setAnimateCompileDropdownArrow: (value: boolean) => void
|
|
|
|
recompileFromScratch: () => void
|
|
|
|
setCompiling: (value: boolean) => void
|
|
|
|
startCompile: (options?: any) => void
|
|
|
|
stopCompile: () => void
|
|
|
|
setChangedAt: (value: any) => void
|
|
|
|
clearCache: () => void
|
|
|
|
syncToEntry: (value: any) => void
|
2021-04-19 08:38:03 -04:00
|
|
|
}
|
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
export const LocalCompileContext = createContext<CompileContext | undefined>(
|
|
|
|
undefined
|
|
|
|
)
|
2022-03-31 07:22:36 -04:00
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
export const LocalCompileProvider: FC = ({ children }) => {
|
2021-10-15 05:39:56 -04:00
|
|
|
const ide = useIdeContext()
|
|
|
|
|
|
|
|
const { hasPremiumCompile, isProjectOwner } = useEditorContext()
|
|
|
|
|
2023-09-18 07:35:43 -04:00
|
|
|
const {
|
|
|
|
_id: projectId,
|
|
|
|
rootDocId,
|
|
|
|
showNewCompileTimeoutUI,
|
|
|
|
} = useProjectContext()
|
2021-10-15 05:39:56 -04:00
|
|
|
|
2022-07-21 04:31:31 -04:00
|
|
|
const { pdfPreviewOpen } = useLayoutContext()
|
|
|
|
|
2022-12-20 08:01:54 -05:00
|
|
|
const { features } = useUserContext()
|
|
|
|
|
2023-10-26 06:01:08 -04:00
|
|
|
const { fileTreeData } = useFileTreeData()
|
|
|
|
const { findEntityByPath } = useFileTreePathContext()
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// whether a compile is in progress
|
|
|
|
const [compiling, setCompiling] = useState(false)
|
|
|
|
|
2022-07-13 04:33:47 -04:00
|
|
|
// whether to show the compile time warning
|
|
|
|
const [showCompileTimeWarning, setShowCompileTimeWarning] = useState(false)
|
|
|
|
|
2021-10-08 05:51:04 -04:00
|
|
|
// the log entries parsed from the compile output log
|
2021-11-03 10:30:41 -04:00
|
|
|
const [logEntries, setLogEntries] = useScopeValueSetterOnly('pdf.logEntries')
|
2021-10-08 05:51:04 -04:00
|
|
|
|
|
|
|
// annotations for display in the editor, built from the log entries
|
2021-11-15 07:50:42 -05:00
|
|
|
const [logEntryAnnotations, setLogEntryAnnotations] = useScopeValue(
|
|
|
|
'pdf.logEntryAnnotations'
|
|
|
|
)
|
2021-10-08 05:51:04 -04:00
|
|
|
|
2023-11-21 09:29:44 -05:00
|
|
|
// the PDF viewer and whether syntax validation is enabled globally
|
|
|
|
const { userSettings } = useUserSettingsContext()
|
|
|
|
const { pdfViewer, syntaxValidation } = userSettings
|
2021-10-21 06:31:51 -04:00
|
|
|
|
2021-10-08 05:51:04 -04:00
|
|
|
// the URL for downloading the PDF
|
2024-01-26 04:23:48 -05:00
|
|
|
const [, setPdfDownloadUrl] =
|
|
|
|
useScopeValueSetterOnly<string>('pdf.downloadUrl')
|
2021-10-08 05:51:04 -04:00
|
|
|
|
|
|
|
// the URL for loading the PDF in the preview pane
|
2024-01-26 04:23:48 -05:00
|
|
|
const [, setPdfUrl] = useScopeValueSetterOnly<string>('pdf.url')
|
2021-10-08 05:51:04 -04:00
|
|
|
|
2022-07-06 07:06:53 -04:00
|
|
|
// low level details for metrics
|
2024-01-26 04:23:48 -05:00
|
|
|
const [pdfFile, setPdfFile] = useState<PdfFile | undefined>()
|
2022-06-21 08:15:26 -04:00
|
|
|
|
2022-07-13 08:56:30 -04:00
|
|
|
useEffect(() => {
|
|
|
|
setPdfDownloadUrl(pdfFile?.pdfDownloadUrl)
|
|
|
|
setPdfUrl(pdfFile?.pdfUrl)
|
|
|
|
}, [pdfFile, setPdfDownloadUrl, setPdfUrl])
|
|
|
|
|
2023-04-14 04:56:24 -04:00
|
|
|
// the project is considered to be "uncompiled" if a doc has changed, or finished saving, since the last compile started.
|
2021-10-21 11:29:27 -04:00
|
|
|
const [uncompiled, setUncompiled] = useScopeValue('pdf.uncompiled')
|
2021-10-08 05:51:04 -04:00
|
|
|
|
2023-04-14 04:56:24 -04:00
|
|
|
// whether a doc has been edited since the last compile started
|
|
|
|
const [editedSinceCompileStarted, setEditedSinceCompileStarted] =
|
|
|
|
useState(false)
|
|
|
|
|
2021-10-08 05:51:04 -04:00
|
|
|
// the id of the CLSI server which ran the compile
|
2021-10-21 06:31:51 -04:00
|
|
|
const [clsiServerId, setClsiServerId] = useState()
|
2021-10-08 05:51:04 -04:00
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// data received in response to a compile request
|
2024-01-26 04:23:48 -05:00
|
|
|
const [data, setData] = useState<Record<string, any>>()
|
2021-10-15 05:39:56 -04:00
|
|
|
|
2023-11-21 09:12:41 -05:00
|
|
|
// the rootDocId used in the most recent compile request, which may not be the
|
|
|
|
// same as the project rootDocId. This is used to calculate correct paths when
|
|
|
|
// parsing the compile logs
|
|
|
|
const lastCompileRootDocId = data?.rootDocId
|
|
|
|
|
2021-10-20 04:45:10 -04:00
|
|
|
// callback to be invoked for PdfJsMetrics
|
2022-07-18 06:24:31 -04:00
|
|
|
const [firstRenderDone, setFirstRenderDone] = useState(() => () => {})
|
2021-10-20 04:45:10 -04:00
|
|
|
|
2022-06-21 08:15:26 -04:00
|
|
|
// latencies of compile/pdf download/rendering
|
|
|
|
const [deliveryLatencies, setDeliveryLatencies] = useState({})
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// whether the project has been compiled yet
|
|
|
|
const [compiledOnce, setCompiledOnce] = useState(false)
|
|
|
|
|
|
|
|
// whether the cache is being cleared
|
|
|
|
const [clearingCache, setClearingCache] = useState(false)
|
|
|
|
|
|
|
|
// whether the logs should be visible
|
|
|
|
const [showLogs, setShowLogs] = useState(false)
|
|
|
|
|
2022-06-21 08:15:26 -04:00
|
|
|
// whether the faster compiles feedback UI should be displayed
|
|
|
|
const [showFasterCompilesFeedbackUI, setShowFasterCompilesFeedbackUI] =
|
|
|
|
useState(false)
|
|
|
|
|
2022-06-13 08:29:35 -04:00
|
|
|
// whether the compile dropdown arrow should be animated
|
|
|
|
const [animateCompileDropdownArrow, setAnimateCompileDropdownArrow] =
|
|
|
|
useState(false)
|
|
|
|
|
2022-03-31 07:22:36 -04:00
|
|
|
const toggleLogs = useCallback(() => {
|
|
|
|
setShowLogs(prev => {
|
|
|
|
if (!prev) {
|
|
|
|
sendMBOnce('ide-open-logs-once')
|
|
|
|
}
|
|
|
|
return !prev
|
|
|
|
})
|
|
|
|
}, [setShowLogs])
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// an error that occurred
|
2024-01-26 04:23:48 -05:00
|
|
|
const [error, setError] = useState<string>()
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// the list of files that can be downloaded
|
2024-01-26 04:23:48 -05:00
|
|
|
const [fileList, setFileList] = useState<Record<string, any[]>>()
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// the raw contents of the log file
|
2024-01-26 04:23:48 -05:00
|
|
|
const [rawLog, setRawLog] = useState<string>()
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// validation issues from CLSI
|
|
|
|
const [validationIssues, setValidationIssues] = useState()
|
|
|
|
|
2021-10-21 06:31:51 -04:00
|
|
|
// areas to highlight on the PDF, from synctex
|
|
|
|
const [highlights, setHighlights] = useState()
|
|
|
|
|
|
|
|
// scroll position of the PDF
|
|
|
|
const [position, setPosition] = usePersistedState(`pdf.position.${projectId}`)
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// whether autocompile is switched on
|
2021-12-21 08:45:38 -05:00
|
|
|
const [autoCompile, setAutoCompile] = usePersistedState(
|
2021-10-15 05:39:56 -04:00
|
|
|
`autocompile_enabled:${projectId}`,
|
|
|
|
false,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
|
|
|
|
// whether the compile should run in draft mode
|
|
|
|
const [draft, setDraft] = usePersistedState(`draft:${projectId}`, false, true)
|
|
|
|
|
2022-06-02 10:35:43 -04:00
|
|
|
// whether compiling should stop on first error
|
|
|
|
const [stopOnFirstError, setStopOnFirstError] = usePersistedState(
|
|
|
|
`stop_on_first_error:${projectId}`,
|
|
|
|
false,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
|
2022-06-07 07:55:48 -04:00
|
|
|
// whether the last compiles stopped on first error
|
|
|
|
const [stoppedOnFirstError, setStoppedOnFirstError] = useState(false)
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// whether compiling should be prevented if there are linting errors
|
|
|
|
const [stopOnValidationError, setStopOnValidationError] = usePersistedState(
|
|
|
|
`stop_on_validation_error:${projectId}`,
|
|
|
|
true,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
|
|
|
|
// the Document currently open in the editor
|
|
|
|
const [currentDoc] = useScopeValue('editor.sharejs_doc')
|
|
|
|
|
|
|
|
// whether the editor linter found errors
|
|
|
|
const [hasLintingError, setHasLintingError] = useScopeValue('hasLintingError')
|
|
|
|
|
2023-04-14 04:56:24 -04:00
|
|
|
// the timestamp that a doc was last changed
|
2021-10-15 05:39:56 -04:00
|
|
|
const [changedAt, setChangedAt] = useState(0)
|
|
|
|
|
|
|
|
const { signal } = useAbortController()
|
|
|
|
|
2021-11-03 10:30:41 -04:00
|
|
|
const cleanupCompileResult = useCallback(() => {
|
2024-01-26 04:23:48 -05:00
|
|
|
setPdfFile(undefined)
|
2021-11-03 10:30:41 -04:00
|
|
|
setLogEntries(null)
|
|
|
|
setLogEntryAnnotations({})
|
2022-07-13 08:56:30 -04:00
|
|
|
}, [setPdfFile, setLogEntries, setLogEntryAnnotations])
|
2021-11-03 10:30:41 -04:00
|
|
|
|
2022-03-03 11:28:12 -05:00
|
|
|
const compilingRef = useRef(false)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
compilingRef.current = compiling
|
|
|
|
}, [compiling])
|
|
|
|
|
2023-10-26 06:01:08 -04:00
|
|
|
const _buildLogEntryAnnotations = useCallback(
|
2023-11-21 09:12:41 -05:00
|
|
|
entries =>
|
|
|
|
buildLogEntryAnnotations(entries, fileTreeData, lastCompileRootDocId),
|
|
|
|
[fileTreeData, lastCompileRootDocId]
|
2023-10-26 06:01:08 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
const buildLogEntryAnnotationsRef = useRef(_buildLogEntryAnnotations)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
buildLogEntryAnnotationsRef.current = _buildLogEntryAnnotations
|
|
|
|
}, [_buildLogEntryAnnotations])
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// the document compiler
|
|
|
|
const [compiler] = useState(() => {
|
|
|
|
return new DocumentCompiler({
|
2022-01-10 10:47:10 -05:00
|
|
|
projectId,
|
2021-10-15 05:39:56 -04:00
|
|
|
setChangedAt,
|
|
|
|
setCompiling,
|
|
|
|
setData,
|
2021-10-20 04:45:10 -04:00
|
|
|
setFirstRenderDone,
|
2022-06-21 08:15:26 -04:00
|
|
|
setDeliveryLatencies,
|
2021-10-15 05:39:56 -04:00
|
|
|
setError,
|
2021-11-03 10:30:41 -04:00
|
|
|
cleanupCompileResult,
|
2022-03-03 11:28:12 -05:00
|
|
|
compilingRef,
|
2021-10-15 05:39:56 -04:00
|
|
|
signal,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// keep currentDoc in sync with the compiler
|
|
|
|
useEffect(() => {
|
|
|
|
compiler.currentDoc = currentDoc
|
|
|
|
}, [compiler, currentDoc])
|
|
|
|
|
2023-11-21 09:12:41 -05:00
|
|
|
// keep the project rootDocId in sync with the compiler
|
|
|
|
useEffect(() => {
|
|
|
|
compiler.projectRootDocId = rootDocId
|
|
|
|
}, [compiler, rootDocId])
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// keep draft setting in sync with the compiler
|
|
|
|
useEffect(() => {
|
2022-06-07 07:55:48 -04:00
|
|
|
compiler.setOption('draft', draft)
|
2021-10-15 05:39:56 -04:00
|
|
|
}, [compiler, draft])
|
|
|
|
|
2022-06-06 07:41:36 -04:00
|
|
|
// keep stop on first error setting in sync with the compiler
|
|
|
|
useEffect(() => {
|
2022-06-07 07:55:48 -04:00
|
|
|
compiler.setOption('stopOnFirstError', stopOnFirstError)
|
2022-06-06 07:41:36 -04:00
|
|
|
}, [compiler, stopOnFirstError])
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
useEffect(() => {
|
2024-01-26 04:26:31 -05:00
|
|
|
setUncompiled(changedAt > 0)
|
|
|
|
}, [setUncompiled, changedAt])
|
2023-04-14 04:56:24 -04:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
setEditedSinceCompileStarted(changedAt > 0)
|
|
|
|
}, [setEditedSinceCompileStarted, changedAt])
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// always compile the PDF once after opening the project, after the doc has loaded
|
|
|
|
useEffect(() => {
|
|
|
|
if (!compiledOnce && currentDoc) {
|
|
|
|
setCompiledOnce(true)
|
|
|
|
compiler.compile({ isAutoCompileOnLoad: true })
|
|
|
|
}
|
|
|
|
}, [compiledOnce, currentDoc, compiler])
|
|
|
|
|
2022-07-13 04:33:47 -04:00
|
|
|
useEffect(() => {
|
2024-01-26 04:23:48 -05:00
|
|
|
const compileTimeWarningEnabled =
|
|
|
|
features?.compileTimeout !== undefined && features.compileTimeout <= 60
|
2022-07-13 04:33:47 -04:00
|
|
|
|
|
|
|
if (compileTimeWarningEnabled && compiling && isProjectOwner) {
|
|
|
|
const timeout = window.setTimeout(() => {
|
|
|
|
setShowCompileTimeWarning(true)
|
|
|
|
}, 30000)
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
window.clearTimeout(timeout)
|
|
|
|
}
|
|
|
|
}
|
2022-12-20 08:01:54 -05:00
|
|
|
}, [compiling, isProjectOwner, features])
|
2022-07-13 04:33:47 -04:00
|
|
|
|
2024-01-23 08:00:09 -05:00
|
|
|
const { splitTestVariants } = useSplitTestContext()
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// handle the data returned from a compile request
|
|
|
|
// note: this should _only_ run when `data` changes,
|
|
|
|
// the other dependencies must all be static
|
|
|
|
useEffect(() => {
|
2022-03-25 05:42:10 -04:00
|
|
|
const abortController = new AbortController()
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
if (data) {
|
|
|
|
if (data.clsiServerId) {
|
|
|
|
setClsiServerId(data.clsiServerId) // set in scope, for PdfSynctexController
|
|
|
|
}
|
2022-06-21 08:15:26 -04:00
|
|
|
setShowFasterCompilesFeedbackUI(
|
|
|
|
Boolean(data.showFasterCompilesFeedbackUI)
|
|
|
|
)
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
if (data.outputFiles) {
|
2022-03-25 05:42:10 -04:00
|
|
|
const outputFiles = new Map()
|
|
|
|
|
|
|
|
for (const outputFile of data.outputFiles) {
|
|
|
|
outputFiles.set(outputFile.path, outputFile)
|
|
|
|
}
|
|
|
|
|
2022-07-13 08:56:30 -04:00
|
|
|
// set the PDF context
|
2022-05-18 06:37:25 -04:00
|
|
|
if (data.status === 'success') {
|
2022-07-13 08:56:30 -04:00
|
|
|
setPdfFile(handleOutputFiles(outputFiles, projectId, data))
|
2022-05-18 06:37:25 -04:00
|
|
|
}
|
2022-03-25 05:42:10 -04:00
|
|
|
|
2022-05-18 06:37:25 -04:00
|
|
|
setFileList(
|
|
|
|
buildFileList(outputFiles, data.clsiServerId, data.compileGroup)
|
|
|
|
)
|
|
|
|
|
|
|
|
// handle log files
|
|
|
|
// asynchronous (TODO: cancel on new compile?)
|
|
|
|
setLogEntryAnnotations(null)
|
|
|
|
setLogEntries(null)
|
2024-01-26 04:23:48 -05:00
|
|
|
setRawLog(undefined)
|
2022-05-18 06:37:25 -04:00
|
|
|
|
|
|
|
handleLogFiles(outputFiles, data, abortController.signal).then(
|
2024-01-26 04:23:48 -05:00
|
|
|
(result: Record<string, any>) => {
|
2022-05-18 06:37:25 -04:00
|
|
|
setRawLog(result.log)
|
|
|
|
setLogEntries(result.logEntries)
|
|
|
|
setLogEntryAnnotations(
|
2023-10-26 06:01:08 -04:00
|
|
|
buildLogEntryAnnotationsRef.current(result.logEntries.all)
|
2022-05-18 06:37:25 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// sample compile stats for real users
|
2024-01-23 08:00:09 -05:00
|
|
|
if (!window.user.alphaProgram) {
|
|
|
|
if (['success', 'stopped-on-first-error'].includes(data.status)) {
|
|
|
|
sendMBSampled(
|
|
|
|
'compile-result',
|
|
|
|
{
|
|
|
|
errors: result.logEntries.errors.length,
|
|
|
|
warnings: result.logEntries.warnings.length,
|
|
|
|
typesetting: result.logEntries.typesetting.length,
|
|
|
|
newPdfPreview: true, // TODO: is this useful?
|
|
|
|
stopOnFirstError: data.options.stopOnFirstError,
|
|
|
|
},
|
|
|
|
0.01
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (splitTestVariants['compile-log-events'] === 'enabled') {
|
|
|
|
sendMB('compile-log-entries', {
|
|
|
|
status: data.status,
|
2022-06-13 08:08:38 -04:00
|
|
|
stopOnFirstError: data.options.stopOnFirstError,
|
2024-01-23 08:00:09 -05:00
|
|
|
isAutoCompileOnLoad: !!data.options.isAutoCompileOnLoad,
|
|
|
|
isAutoCompileOnChange: !!data.options.isAutoCompileOnChange,
|
2024-02-05 06:41:49 -05:00
|
|
|
...buildRuleCounts(result.logEntries.all),
|
2024-01-23 08:00:09 -05:00
|
|
|
})
|
|
|
|
}
|
2022-03-25 05:42:10 -04:00
|
|
|
}
|
2022-05-18 06:37:25 -04:00
|
|
|
}
|
|
|
|
)
|
2021-10-15 05:39:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (data.status) {
|
|
|
|
case 'success':
|
|
|
|
setError(undefined)
|
|
|
|
setShowLogs(false)
|
|
|
|
break
|
|
|
|
|
2022-06-07 07:55:48 -04:00
|
|
|
case 'stopped-on-first-error':
|
|
|
|
setError(undefined)
|
|
|
|
setShowLogs(true)
|
|
|
|
break
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
case 'clsi-maintenance':
|
|
|
|
case 'compile-in-progress':
|
|
|
|
case 'exited':
|
|
|
|
case 'failure':
|
|
|
|
case 'project-too-large':
|
|
|
|
case 'rate-limited':
|
|
|
|
case 'terminated':
|
|
|
|
case 'too-recently-compiled':
|
|
|
|
setError(data.status)
|
|
|
|
break
|
|
|
|
|
|
|
|
case 'timedout':
|
|
|
|
setError('timedout')
|
|
|
|
|
|
|
|
if (!hasPremiumCompile && isProjectOwner) {
|
|
|
|
send(
|
|
|
|
'subscription-funnel',
|
|
|
|
'editor-click-feature',
|
|
|
|
'compile-timeout'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
break
|
|
|
|
|
|
|
|
case 'autocompile-backoff':
|
|
|
|
if (!data.options.isAutoCompileOnLoad) {
|
|
|
|
setError('autocompile-disabled')
|
|
|
|
setAutoCompile(false)
|
|
|
|
}
|
|
|
|
break
|
|
|
|
|
|
|
|
case 'unavailable':
|
|
|
|
setError('clsi-unavailable')
|
|
|
|
break
|
|
|
|
|
|
|
|
case 'validation-problems':
|
|
|
|
setError('validation-problems')
|
|
|
|
setValidationIssues(data.validationProblems)
|
|
|
|
break
|
|
|
|
|
|
|
|
default:
|
|
|
|
setError('error')
|
|
|
|
break
|
|
|
|
}
|
2022-06-07 07:55:48 -04:00
|
|
|
|
|
|
|
setStoppedOnFirstError(data.status === 'stopped-on-first-error')
|
2021-10-15 05:39:56 -04:00
|
|
|
}
|
2022-03-25 05:42:10 -04:00
|
|
|
|
|
|
|
return () => {
|
|
|
|
abortController.abort()
|
|
|
|
}
|
2021-10-15 05:39:56 -04:00
|
|
|
}, [
|
|
|
|
data,
|
|
|
|
ide,
|
|
|
|
hasPremiumCompile,
|
|
|
|
isProjectOwner,
|
|
|
|
projectId,
|
|
|
|
setAutoCompile,
|
|
|
|
setClsiServerId,
|
|
|
|
setLogEntries,
|
|
|
|
setLogEntryAnnotations,
|
2022-07-06 07:06:53 -04:00
|
|
|
setPdfFile,
|
2024-01-23 08:00:09 -05:00
|
|
|
splitTestVariants,
|
2021-10-15 05:39:56 -04:00
|
|
|
])
|
|
|
|
|
|
|
|
// switch to logs if there's an error
|
|
|
|
useEffect(() => {
|
|
|
|
if (error) {
|
|
|
|
setShowLogs(true)
|
|
|
|
}
|
|
|
|
}, [error])
|
|
|
|
|
|
|
|
// whether there has been an autocompile linting error, if syntax validation is switched on
|
|
|
|
const autoCompileLintingError = Boolean(
|
|
|
|
autoCompile && syntaxValidation && hasLintingError
|
|
|
|
)
|
|
|
|
|
|
|
|
const codeCheckFailed = stopOnValidationError && autoCompileLintingError
|
|
|
|
|
|
|
|
// the project is available for auto-compiling
|
2022-07-21 04:31:31 -04:00
|
|
|
// (autocompile is enabled, the PDF preview is open, and the code check (if enabled) hasn't failed)
|
|
|
|
const canAutoCompile = Boolean(
|
|
|
|
autoCompile && pdfPreviewOpen && !codeCheckFailed
|
|
|
|
)
|
2021-10-21 06:31:51 -04:00
|
|
|
|
|
|
|
// show that the project has pending changes
|
|
|
|
const hasChanges = Boolean(canAutoCompile && uncompiled && compiledOnce)
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// call the debounced autocompile function if the project is available for auto-compiling and it has changed
|
|
|
|
useEffect(() => {
|
2021-10-21 06:31:51 -04:00
|
|
|
if (canAutoCompile) {
|
2024-01-26 04:26:31 -05:00
|
|
|
if (changedAt > 0) {
|
2021-10-21 06:31:51 -04:00
|
|
|
compiler.debouncedAutoCompile()
|
|
|
|
}
|
2021-10-15 05:39:56 -04:00
|
|
|
} else {
|
|
|
|
compiler.debouncedAutoCompile.cancel()
|
|
|
|
}
|
2024-01-26 04:26:31 -05:00
|
|
|
}, [compiler, canAutoCompile, changedAt])
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// cancel debounced recompile on unmount
|
|
|
|
useEffect(() => {
|
|
|
|
return () => {
|
|
|
|
compiler.debouncedAutoCompile.cancel()
|
|
|
|
}
|
|
|
|
}, [compiler])
|
|
|
|
|
|
|
|
// start a compile manually
|
2021-11-30 09:54:14 -05:00
|
|
|
const startCompile = useCallback(
|
|
|
|
options => {
|
|
|
|
compiler.compile(options)
|
|
|
|
},
|
|
|
|
[compiler]
|
|
|
|
)
|
2021-10-15 05:39:56 -04:00
|
|
|
|
|
|
|
// stop a compile manually
|
|
|
|
const stopCompile = useCallback(() => {
|
|
|
|
compiler.stopCompile()
|
|
|
|
}, [compiler])
|
|
|
|
|
|
|
|
// clear the compile cache
|
|
|
|
const clearCache = useCallback(() => {
|
|
|
|
setClearingCache(true)
|
|
|
|
|
2021-12-07 04:49:18 -05:00
|
|
|
return compiler
|
|
|
|
.clearCache()
|
|
|
|
.then(() => {
|
|
|
|
setFileList(undefined)
|
2022-07-13 08:56:30 -04:00
|
|
|
setPdfFile(undefined)
|
2021-12-07 04:49:18 -05:00
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
setClearingCache(false)
|
|
|
|
})
|
2022-07-13 08:56:30 -04:00
|
|
|
}, [compiler])
|
2021-10-15 05:39:56 -04:00
|
|
|
|
2023-05-15 05:18:30 -04:00
|
|
|
const syncToEntry = useCallback(
|
|
|
|
entry => {
|
2023-10-26 06:01:08 -04:00
|
|
|
const result = findEntityByPath(entry.file)
|
2023-05-15 05:18:30 -04:00
|
|
|
|
2023-10-26 06:01:08 -04:00
|
|
|
if (result && result.type === 'doc') {
|
|
|
|
ide.editorManager.openDocId(result.entity._id, {
|
2023-05-15 05:18:30 -04:00
|
|
|
gotoLine: entry.line ?? undefined,
|
|
|
|
gotoColumn: entry.column ?? undefined,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2023-10-26 06:01:08 -04:00
|
|
|
[findEntityByPath, ide.editorManager]
|
2023-05-15 05:18:30 -04:00
|
|
|
)
|
|
|
|
|
2021-10-15 05:39:56 -04:00
|
|
|
// clear the cache then run a compile, triggered by a menu item
|
|
|
|
const recompileFromScratch = useCallback(() => {
|
|
|
|
clearCache().then(() => {
|
|
|
|
compiler.compile()
|
|
|
|
})
|
|
|
|
}, [clearCache, compiler])
|
|
|
|
|
2022-06-09 10:47:53 -04:00
|
|
|
// After a compile, the compiler sets `data.options` to the options that were
|
|
|
|
// used for that compile.
|
|
|
|
const lastCompileOptions = useMemo(() => data?.options || {}, [data])
|
|
|
|
|
2021-10-08 05:51:04 -04:00
|
|
|
const value = useMemo(
|
|
|
|
() => ({
|
2022-06-13 08:29:35 -04:00
|
|
|
animateCompileDropdownArrow,
|
2021-10-15 05:39:56 -04:00
|
|
|
autoCompile,
|
|
|
|
clearCache,
|
|
|
|
clearingCache,
|
2021-10-08 05:51:04 -04:00
|
|
|
clsiServerId,
|
2021-10-15 05:39:56 -04:00
|
|
|
codeCheckFailed,
|
|
|
|
compiling,
|
2022-06-21 08:15:26 -04:00
|
|
|
deliveryLatencies,
|
2021-10-15 05:39:56 -04:00
|
|
|
draft,
|
2023-04-14 04:56:24 -04:00
|
|
|
editedSinceCompileStarted,
|
2021-10-15 05:39:56 -04:00
|
|
|
error,
|
|
|
|
fileList,
|
|
|
|
hasChanges,
|
2021-10-21 06:31:51 -04:00
|
|
|
highlights,
|
2023-09-18 07:35:43 -04:00
|
|
|
isProjectOwner,
|
2022-06-09 10:47:53 -04:00
|
|
|
lastCompileOptions,
|
2021-11-15 07:50:42 -05:00
|
|
|
logEntryAnnotations,
|
2021-10-08 05:51:04 -04:00
|
|
|
logEntries,
|
2022-07-13 08:56:30 -04:00
|
|
|
pdfDownloadUrl: pdfFile?.pdfDownloadUrl,
|
2022-07-06 07:06:53 -04:00
|
|
|
pdfFile,
|
2022-07-13 08:56:30 -04:00
|
|
|
pdfUrl: pdfFile?.pdfUrl,
|
2021-10-21 06:31:51 -04:00
|
|
|
pdfViewer,
|
|
|
|
position,
|
2021-10-15 05:39:56 -04:00
|
|
|
rawLog,
|
|
|
|
recompileFromScratch,
|
2022-06-13 08:29:35 -04:00
|
|
|
setAnimateCompileDropdownArrow,
|
2021-10-15 05:39:56 -04:00
|
|
|
setAutoCompile,
|
|
|
|
setCompiling,
|
|
|
|
setDraft,
|
2021-10-15 05:52:07 -04:00
|
|
|
setError,
|
2021-10-15 05:39:56 -04:00
|
|
|
setHasLintingError, // only for stories
|
2021-10-21 06:31:51 -04:00
|
|
|
setHighlights,
|
|
|
|
setPosition,
|
2022-07-13 04:33:47 -04:00
|
|
|
showCompileTimeWarning,
|
|
|
|
setShowCompileTimeWarning,
|
2021-10-15 05:39:56 -04:00
|
|
|
setShowLogs,
|
2022-03-31 07:22:36 -04:00
|
|
|
toggleLogs,
|
2022-06-02 10:35:43 -04:00
|
|
|
setStopOnFirstError,
|
2021-10-15 05:39:56 -04:00
|
|
|
setStopOnValidationError,
|
|
|
|
showLogs,
|
2023-09-18 07:35:43 -04:00
|
|
|
showNewCompileTimeoutUI,
|
2022-06-21 08:15:26 -04:00
|
|
|
showFasterCompilesFeedbackUI,
|
2021-10-15 05:39:56 -04:00
|
|
|
startCompile,
|
|
|
|
stopCompile,
|
2022-06-02 10:35:43 -04:00
|
|
|
stopOnFirstError,
|
2021-10-15 05:39:56 -04:00
|
|
|
stopOnValidationError,
|
2022-06-07 07:55:48 -04:00
|
|
|
stoppedOnFirstError,
|
2021-10-08 05:51:04 -04:00
|
|
|
uncompiled,
|
2021-10-15 05:39:56 -04:00
|
|
|
validationIssues,
|
2021-10-20 04:45:10 -04:00
|
|
|
firstRenderDone,
|
2021-11-30 09:54:14 -05:00
|
|
|
setChangedAt,
|
|
|
|
cleanupCompileResult,
|
2023-05-15 05:18:30 -04:00
|
|
|
syncToEntry,
|
2021-10-08 05:51:04 -04:00
|
|
|
}),
|
|
|
|
[
|
2022-06-13 08:29:35 -04:00
|
|
|
animateCompileDropdownArrow,
|
2021-10-15 05:39:56 -04:00
|
|
|
autoCompile,
|
|
|
|
clearCache,
|
|
|
|
clearingCache,
|
2021-10-08 05:51:04 -04:00
|
|
|
clsiServerId,
|
2021-10-15 05:39:56 -04:00
|
|
|
codeCheckFailed,
|
|
|
|
compiling,
|
2022-06-21 08:15:26 -04:00
|
|
|
deliveryLatencies,
|
2021-10-15 05:39:56 -04:00
|
|
|
draft,
|
2023-04-14 04:56:24 -04:00
|
|
|
editedSinceCompileStarted,
|
2021-10-15 05:39:56 -04:00
|
|
|
error,
|
|
|
|
fileList,
|
|
|
|
hasChanges,
|
2021-10-21 06:31:51 -04:00
|
|
|
highlights,
|
2023-09-18 07:35:43 -04:00
|
|
|
isProjectOwner,
|
2022-06-09 10:47:53 -04:00
|
|
|
lastCompileOptions,
|
2021-10-08 05:51:04 -04:00
|
|
|
logEntries,
|
2021-11-15 07:50:42 -05:00
|
|
|
logEntryAnnotations,
|
2021-10-21 06:31:51 -04:00
|
|
|
position,
|
2022-07-06 07:06:53 -04:00
|
|
|
pdfFile,
|
2021-10-21 06:31:51 -04:00
|
|
|
pdfViewer,
|
2021-10-15 05:39:56 -04:00
|
|
|
rawLog,
|
|
|
|
recompileFromScratch,
|
2022-06-13 08:29:35 -04:00
|
|
|
setAnimateCompileDropdownArrow,
|
2021-10-15 05:39:56 -04:00
|
|
|
setAutoCompile,
|
|
|
|
setDraft,
|
2021-10-15 05:52:07 -04:00
|
|
|
setError,
|
2021-11-03 10:30:41 -04:00
|
|
|
setHasLintingError, // only for stories
|
2021-10-21 06:31:51 -04:00
|
|
|
setHighlights,
|
|
|
|
setPosition,
|
2022-07-13 04:33:47 -04:00
|
|
|
setShowCompileTimeWarning,
|
2022-06-02 10:35:43 -04:00
|
|
|
setStopOnFirstError,
|
2021-10-15 05:39:56 -04:00
|
|
|
setStopOnValidationError,
|
2022-07-13 04:33:47 -04:00
|
|
|
showCompileTimeWarning,
|
2021-10-15 05:39:56 -04:00
|
|
|
showLogs,
|
2023-09-18 07:35:43 -04:00
|
|
|
showNewCompileTimeoutUI,
|
2022-06-21 08:15:26 -04:00
|
|
|
showFasterCompilesFeedbackUI,
|
2021-10-15 05:39:56 -04:00
|
|
|
startCompile,
|
|
|
|
stopCompile,
|
2022-06-02 10:35:43 -04:00
|
|
|
stopOnFirstError,
|
2021-10-15 05:39:56 -04:00
|
|
|
stopOnValidationError,
|
2022-06-07 07:55:48 -04:00
|
|
|
stoppedOnFirstError,
|
2021-10-08 05:51:04 -04:00
|
|
|
uncompiled,
|
2021-10-15 05:39:56 -04:00
|
|
|
validationIssues,
|
2021-10-20 04:45:10 -04:00
|
|
|
firstRenderDone,
|
2021-11-30 09:54:14 -05:00
|
|
|
setChangedAt,
|
|
|
|
cleanupCompileResult,
|
2022-03-31 07:22:36 -04:00
|
|
|
setShowLogs,
|
|
|
|
toggleLogs,
|
2023-05-15 05:18:30 -04:00
|
|
|
syncToEntry,
|
2021-10-08 05:51:04 -04:00
|
|
|
]
|
|
|
|
)
|
2021-04-19 08:38:03 -04:00
|
|
|
|
|
|
|
return (
|
2022-03-31 07:22:36 -04:00
|
|
|
<LocalCompileContext.Provider value={value}>
|
|
|
|
{children}
|
|
|
|
</LocalCompileContext.Provider>
|
2021-04-19 08:38:03 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-01-26 04:23:48 -05:00
|
|
|
export function useLocalCompileContext() {
|
|
|
|
const context = useContext(LocalCompileContext)
|
|
|
|
if (!context) {
|
|
|
|
throw new Error(
|
|
|
|
'useLocalCompileContext is only available inside LocalCompileProvider'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return context
|
2021-04-19 08:38:03 -04:00
|
|
|
}
|