diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index bd611020bd..f633060aaf 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -32,7 +32,7 @@ div.full-size.pdf(ng-controller="PdfController") a.log-btn( href ng-click="toggleLogs()" - ng-class="{ 'active': (pdf.view == 'logs' || pdf.failure) && !pdf.error && !pdf.timeout && !pdf.uncompiled }" + ng-class="{ 'active': shouldShowLogs == true }" tooltip="#{translate('logs_and_output_files')}" tooltip-placement="bottom" ) @@ -74,95 +74,10 @@ div.full-size.pdf(ng-controller="PdfController") ) i.split-screen i.split-screen + // end of toolbar - .pdf-viewer(ng-show="pdf.url && pdf.view == 'pdf' && !pdf.failure && !pdf.timeout && !pdf.error") - div( - pdfng - ng-if="settings.pdfViewer == 'pdfjs'" - pdf-src="pdf.url" - key="{{ project_id }}" - resize-on="layout:main:resize,layout:pdf:resize" - highlights="pdf.highlights" - position="pdf.position" - dbl-click-callback="syncToCode" - ) - - iframe( - ng-src="{{ pdf.url }}" - ng-if="settings.pdfViewer == 'native'" - ) - - .pdf-uncompiled(ng-show="pdf.uncompiled && !pdf.compiling") - |   - i.fa.fa-level-up.fa-flip-horizontal.fa-2x - |   #{translate('click_here_to_preview_pdf')} - - .pdf-errors(ng-show="pdf.timedout || pdf.error") - .alert.alert-danger(ng-show="pdf.error") - strong #{translate("server_error")} - span #{translate("somthing_went_wrong_compiling")} - - - .alert.alert-danger(ng-show="pdf.timedout") - p - strong #{translate("timedout")}. - span #{translate("proj_timed_out_reason")} - p - a.text-info(href="https://www.sharelatex.com/learn/Debugging_Compilation_timeout_errors", target="_blank") - | #{translate("learn_how_to_make_documents_compile_quickly")} - - .alert.alert-success(ng-show="pdf.timedout && !hasPremiumCompile") - p(ng-if="project.owner._id == user.id") - strong #{translate("upgrade_for_faster_compiles")} - p(ng-if="project.owner._id != user.id") - strong #{translate("ask_proj_owner_to_upgrade_for_faster_compiles")} - p #{translate("free_accounts_have_timeout_upgrade_to_increase")} - p Plus: - p - ul.list-unstyled - li - i.fa.fa-check   - | #{translate("unlimited_projects")} - - li - i.fa.fa-check   - | #{translate("collabs_per_proj", {collabcount:'Multiple'})} - - li - i.fa.fa-check   - | #{translate("full_doc_history")} - - li - i.fa.fa-check   - | #{translate("sync_to_dropbox")} - - li - i.fa.fa-check   - | #{translate("sync_to_github")} - - li - i.fa.fa-check   - |#{translate("compile_larger_projects")} - - p(ng-controller="FreeTrialModalController", ng-if="project.owner._id == user.id") - a.btn.btn-success.row-spaced-small( - href - ng-class="buttonClass" - sixpack-convert="track_changes_feature_info" - ng-click="startFreeTrial('compile-timeout')" - ) #{translate("start_free_trial")} - - .pdf-errors(ng-show="pdf.projectTooLarge") - .alert.alert-danger - strong #{translate("project_too_large")} - span #{translate("project_too_large_please_reduce")} - - - - - - - .pdf-logs(ng-show="(pdf.view == 'logs' || pdf.failure) && !pdf.error && !pdf.timeout && !pdf.uncompiled") + // logs view + .pdf-logs(ng-show="shouldShowLogs") .alert.alert-success(ng-show="pdf.logEntries.all.length == 0") | #{translate("no_errors_good_job")} @@ -214,6 +129,90 @@ div.full-size.pdf(ng-controller="PdfController") span(ng-show="pdf.showRawLog") #{translate("hide_raw_logs")} pre(ng-bind="pdf.rawLog", ng-show="pdf.showRawLog") + + + // non-log views (pdf and errors) + div(ng-show="!shouldShowLogs", ng-switch on="pdf.view") + .pdf-uncompiled(ng-switch-when="uncompiled" ng-show="!pdf.compiling") + |   + i.fa.fa-level-up.fa-flip-horizontal.fa-2x + |   #{translate('click_here_to_preview_pdf')} + + .pdf-viewer(ng-switch-when="pdf") + div( + pdfng + ng-if="settings.pdfViewer == 'pdfjs'" + pdf-src="pdf.url" + key="{{ project_id }}" + resize-on="layout:main:resize,layout:pdf:resize" + highlights="pdf.highlights" + position="pdf.position" + dbl-click-callback="syncToCode" + ) + iframe( + ng-src="{{ pdf.url }}" + ng-if="settings.pdfViewer == 'native'" + ) + + .pdf-errors(ng-switch-when="errors") + + .alert.alert-danger(ng-show="pdf.error || pdf.renderingError") + strong #{translate("server_error")} + span #{translate("somthing_went_wrong_compiling")} + + .alert.alert-danger(ng-show="pdf.clsiMaintenance") + strong #{translate("server_error")} + span #{translate("clsi_maintenance")} + + .alert.alert-danger(ng-show="pdf.tooRecentlyCompiled") + strong #{translate("server_error")} + span #{translate("too_recently_compiled")} + + .alert.alert-danger(ng-show="pdf.timedout") + p + strong #{translate("timedout")}. + span #{translate("proj_timed_out_reason")} + p + a.text-info(href="https://www.sharelatex.com/learn/Debugging_Compilation_timeout_errors", target="_blank") + | #{translate("learn_how_to_make_documents_compile_quickly")} + + .alert.alert-success(ng-show="pdf.timedout && !hasPremiumCompile") + p(ng-if="project.owner._id == user.id") + strong #{translate("upgrade_for_faster_compiles")} + p(ng-if="project.owner._id != user.id") + strong #{translate("ask_proj_owner_to_upgrade_for_faster_compiles")} + p #{translate("free_accounts_have_timeout_upgrade_to_increase")} + p Plus: + p + ul.list-unstyled + li + i.fa.fa-check   + | #{translate("unlimited_projects")} + li + i.fa.fa-check   + | #{translate("collabs_per_proj", {collabcount:'Multiple'})} + li + i.fa.fa-check   + | #{translate("full_doc_history")} + li + i.fa.fa-check   + | #{translate("sync_to_dropbox")} + li + i.fa.fa-check   + | #{translate("sync_to_github")} + li + i.fa.fa-check   + |#{translate("compile_larger_projects")} + p(ng-controller="FreeTrialModalController", ng-if="project.owner._id == user.id") + a.btn.btn-success.row-spaced-small( + href + ng-class="buttonClass" + sixpack-convert="track_changes_feature_info" + ng-click="startFreeTrial('compile-timeout')" + ) #{translate("start_free_trial")} + // // // // + + script(type='text/ng-template', id='clearCacheModalTemplate') .modal-header diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee index d2341f04f8..32a60370c1 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee @@ -1,9 +1,9 @@ define [ "ide/editor/directives/aceEditor/auto-complete/SuggestionManager" - "ide/editor/directives/aceEditor/auto-complete/Snippets" + "ide/editor/directives/aceEditor/auto-complete/SnippetManager" "ace/ace" "ace/ext-language_tools" -], (SuggestionManager, Snippets) -> +], (SuggestionManager, SnippetManager) -> Range = ace.require("ace/range").Range getLastCommandFragment = (lineUpToCursor) -> @@ -38,9 +38,7 @@ define [ enableLiveAutocompletion: false }) - SnippetCompleter = - getCompletions: (editor, session, pos, prefix, callback) -> - callback null, Snippets + SnippetCompleter = new SnippetManager() references = @$scope.$root._references ReferencesCompleter = diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SnippetManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SnippetManager.coffee new file mode 100644 index 0000000000..7b7593565d --- /dev/null +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SnippetManager.coffee @@ -0,0 +1,159 @@ +define () -> + environments = [ + "abstract", + "align", "align*", + "equation", "equation*", + "gather", "gather*", + "multline", "multline*", + "split", + "verbatim" + ] + + staticSnippets = for env in environments + { + caption: "\\begin{#{env}}..." + snippet: """ + \\begin{#{env}} + \t$1 + \\end{#{env}} + """ + meta: "env" + } + + staticSnippets = staticSnippets.concat [{ + caption: "\\begin{array}..." + snippet: """ + \\begin{array}{${1:cc}} + \t$2 & $3 \\\\\\\\ + \t$4 & $5 + \\end{array} + """ + meta: "env" + }, { + caption: "\\begin{figure}..." + snippet: """ + \\begin{figure} + \t\\centering + \t\\includegraphics{$1} + \t\\caption{${2:Caption}} + \t\\label{${3:fig:my_label}} + \\end{figure} + """ + meta: "env" + }, { + caption: "\\begin{tabular}..." + snippet: """ + \\begin{tabular}{${1:c|c}} + \t$2 & $3 \\\\\\\\ + \t$4 & $5 + \\end{tabular} + """ + meta: "env" + }, { + caption: "\\begin{table}..." + snippet: """ + \\begin{table}[$1] + \t\\centering + \t\\begin{tabular}{${2:c|c}} + \t\t$3 & $4 \\\\\\\\ + \t\t$5 & $6 + \t\\end{tabular} + \t\\caption{${7:Caption}} + \t\\label{${8:tab:my_label}} + \\end{table} + """ + meta: "env" + }, { + caption: "\\begin{list}..." + snippet: """ + \\begin{list} + \t\\item $1 + \\end{list} + """ + meta: "env" + }, { + caption: "\\begin{enumerate}..." + snippet: """ + \\begin{enumerate} + \t\\item $1 + \\end{enumerate} + """ + meta: "env" + }, { + caption: "\\begin{itemize}..." + snippet: """ + \\begin{itemize} + \t\\item $1 + \\end{itemize} + """ + meta: "env" + }, { + caption: "\\begin{frame}..." + snippet: """ + \\begin{frame}{${1:Frame Title}} + \t$2 + \\end{frame} + """ + meta: "env" + }] + + + parseCustomEnvironments = (text) -> + re = /^\\newenvironment{(\w+)}.*$/gm + result = [] + iterations = 0 + while match = re.exec(text) + result.push {name: match[1], whitespace: null} + iterations += 1 + if iterations >= 1000 + return result + return result + + + parseBeginCommands = (text) -> + re = /^\\begin{(\w+)}.*\n([\t ]*).*$/gm + result = [] + iterations = 0 + while match = re.exec(text) + result.push {name: match[1], whitespace: match[2]} + iterations += 1 + if iterations >= 1000 + return result + return result + + class SnippetManager + getCompletions: (editor, session, pos, prefix, callback) -> + docText = session.getValue() + customEnvironments = parseCustomEnvironments(docText) + beginCommands = parseBeginCommands(docText) + parsedItemsMap = {} + for environment in customEnvironments + parsedItemsMap[environment.name] = environment + for command in beginCommands + parsedItemsMap[command.name] = command + parsedItems = _.values(parsedItemsMap) + snippets = staticSnippets.concat( + parsedItems.map (item) -> + { + caption: "\\begin{#{item.name}}..." + snippet: """ + \\begin{#{item.name}} + #{item.whitespace || ''}$0 + \\end{#{item.name}} + """ + meta: "env" + } + ).concat( + # arguably these `end` commands shouldn't be here, as they're not snippets + # but this is where we have access to the `begin` environment names + # *shrug* + parsedItems.map (item) -> + { + caption: "\\end{#{item.name}}" + value: "\\end{#{item.name}}" + meta: "env" + } + ) + callback null, snippets + + return SnippetManager diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Snippets.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Snippets.coffee deleted file mode 100644 index 4bc3d16ef4..0000000000 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Snippets.coffee +++ /dev/null @@ -1,100 +0,0 @@ -define () -> - environments = [ - "abstract", - "align", "align*", - "equation", "equation*", - "gather", "gather*", - "multline", "multline*", - "split", - "verbatim" - ] - - snippets = for env in environments - { - caption: "\\begin{#{env}}..." - snippet: """ - \\begin{#{env}} - \t$1 - \\end{#{env}} - """ - meta: "env" - } - - snippets = snippets.concat [{ - caption: "\\begin{array}..." - snippet: """ - \\begin{array}{${1:cc}} - \t$2 & $3 \\\\\\\\ - \t$4 & $5 - \\end{array} - """ - meta: "env" - }, { - caption: "\\begin{figure}..." - snippet: """ - \\begin{figure} - \t\\centering - \t\\includegraphics{$1} - \t\\caption{${2:Caption}} - \t\\label{${3:fig:my_label}} - \\end{figure} - """ - meta: "env" - }, { - caption: "\\begin{tabular}..." - snippet: """ - \\begin{tabular}{${1:c|c}} - \t$2 & $3 \\\\\\\\ - \t$4 & $5 - \\end{tabular} - """ - meta: "env" - }, { - caption: "\\begin{table}..." - snippet: """ - \\begin{table}[$1] - \t\\centering - \t\\begin{tabular}{${2:c|c}} - \t\t$3 & $4 \\\\\\\\ - \t\t$5 & $6 - \t\\end{tabular} - \t\\caption{${7:Caption}} - \t\\label{${8:tab:my_label}} - \\end{table} - """ - meta: "env" - }, { - caption: "\\begin{list}..." - snippet: """ - \\begin{list} - \t\\item $1 - \\end{list} - """ - meta: "env" - }, { - caption: "\\begin{enumerate}..." - snippet: """ - \\begin{enumerate} - \t\\item $1 - \\end{enumerate} - """ - meta: "env" - }, { - caption: "\\begin{itemize}..." - snippet: """ - \\begin{itemize} - \t\\item $1 - \\end{itemize} - """ - meta: "env" - }, { - caption: "\\begin{frame}..." - snippet: """ - \\begin{frame}{${1:Frame Title}} - \t$2 - \\end{frame} - """ - meta: "env" - }] - - return snippets \ No newline at end of file diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SuggestionManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SuggestionManager.coffee index 559a2c5981..e0c3710358 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SuggestionManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/SuggestionManager.coffee @@ -28,7 +28,7 @@ define [], () -> # Ignore single letter commands since auto complete is moot then. commandRegex: /\\([a-zA-Z][a-zA-Z]+)/ - + nextCommand: () -> i = @doc.search(@commandRegex) if i == -1 @@ -123,4 +123,3 @@ define [], () -> completionBeforeCursor: completionBeforeCursor completionAfterCursor: completionAfterCursor } - diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index 8586d218a7..5847b58e3e 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -4,7 +4,13 @@ define [ "libs/bib-log-parser" ], (App, LogParser, BibLogParser) -> App.controller "PdfController", ($scope, $http, ide, $modal, synctex, event_tracking, localStorage) -> + autoCompile = true + + # pdf.view = uncompiled | pdf | errors + $scope.pdf.view = if $scope?.pdf?.url then 'pdf' else 'uncompiled' + $scope.shouldShowLogs = false + $scope.$on "project:joined", () -> return if !autoCompile autoCompile = false @@ -12,7 +18,8 @@ define [ $scope.hasPremiumCompile = $scope.project.features.compileGroup == "priority" $scope.$on "pdf:error:display", () -> - $scope.pdf.error = true + $scope.pdf.view = 'errors' + $scope.pdf.renderingError = true $scope.draft = localStorage("draft:#{$scope.project_id}") or false $scope.$watch "draft", (new_value, old_value) -> @@ -37,17 +44,32 @@ define [ $scope.pdf.uncompiled = false $scope.pdf.projectTooLarge = false $scope.pdf.url = null + $scope.pdf.clsiMaintenance = false + $scope.pdf.tooRecentlyCompiled = false if response.status == "timedout" + $scope.pdf.view = 'errors' $scope.pdf.timedout = true else if response.status == "autocompile-backoff" + $scope.pdf.view = 'errors' $scope.pdf.uncompiled = true else if response.status == "project-too-large" + $scope.pdf.view = 'errors' $scope.pdf.projectTooLarge = true else if response.status == "failure" + $scope.pdf.view = 'errors' $scope.pdf.failure = true + $scope.shouldShowLogs = true fetchLogs() + else if response.status == 'clsi-maintenance' + $scope.pdf.view = 'errors' + $scope.pdf.clsiMaintenance = true + else if response.status == "too-recently-compiled" + $scope.pdf.view = 'errors' + $scope.pdf.tooRecentlyCompiled = true else if response.status == "success" + $scope.pdf.view = 'pdf' + $scope.shouldShowLogs = false # define the base url $scope.pdf.url = "/project/#{$scope.project_id}/output/output.pdf?cache_bust=#{Date.now()}" # add a query string parameter for the compile group @@ -116,7 +138,7 @@ define [ entries.warnings = entries.warnings.concat(biberLogEntries.warnings) proceed() .error (e) -> - console.error ">> error", e + # it's not an error for the output.blg file to not be present proceed() # # # # .error () -> @@ -158,6 +180,7 @@ define [ .error () -> $scope.pdf.compiling = false $scope.pdf.error = true + $scope.pdf.view = 'errors' # This needs to be public. ide.$scope.recompile = $scope.recompile @@ -171,13 +194,11 @@ define [ } $scope.toggleLogs = () -> - if !$scope.pdf.view? or $scope.pdf.view == "pdf" - $scope.pdf.view = "logs" - else - $scope.pdf.view = "pdf" + $scope.shouldShowLogs = !$scope.shouldShowLogs $scope.showPdf = () -> $scope.pdf.view = "pdf" + $scope.shouldShowLogs = false $scope.toggleRawLog = () -> $scope.pdf.showRawLog = !$scope.pdf.showRawLog