import { ajax } from 'rxjs/ajax';
import { catchError, map, tap } from 'rxjs/operators';
import { MarkupContent } from 'vscode-languageserver-types';
import { makeRepoURI } from '../repo';
import { normalizeAjaxError } from '../util/errors';
import { memoizeObservable } from '../util/memoize';
export const isEmptyHover = (hover) => !hover ||
    !hover.contents ||
    (Array.isArray(hover.contents) && hover.contents.length === 0) ||
    hover.contents.every(c => {
        if (MarkupContent.is(c)) {
            return !c.value;
        }
        if (typeof c === 'string') {
            return !c;
        }
        return !c.value;
    });
/** LSP proxy error code for unsupported modes */
export const EMODENOTFOUND = -32000;
export function sendLSPHTTPRequests(requests, urlPathHint) {
    if (!urlPathHint) {
        urlPathHint = requests[1] && requests[1].method;
    }
    return ajax({
        method: 'POST',
        url: `/.api/xlang/${urlPathHint || '_'}`,
        headers: Object.assign({}, window.context.xhrHeaders, { Accept: 'application/json', 'Content-Type': 'application/json' }),
        body: JSON.stringify(requests),
    }).pipe(
    // Workaround for https://github.com/ReactiveX/rxjs/issues/3606
    tap(response => {
        if (response.status === 0) {
            throw Object.assign(new Error('Ajax status 0'), response);
        }
    }), catchError(err => {
        normalizeAjaxError(err);
        throw err;
    }), map(({ response }) => response));
}
const httpSendLSPRequest = (ctx, request) => sendLSPHTTPRequests([
    {
        id: 0,
        method: 'initialize',
        params: {
            rootUri: `git://${ctx.repoPath}?${ctx.commitID}`,
            mode: ctx.mode,
            initializationOptions: { mode: ctx.mode },
        },
    },
    request ? Object.assign({ id: 1 }, request) : null,
    { id: 2, method: 'shutdown' },
    { method: 'exit' },
].filter(m => m !== null), request ? request.method : 'initialize').pipe(map((results) => {
    for (const result of results) {
        if (result && result.error) {
            throw Object.assign(new Error(result.error.message), result.error, { responses: results });
        }
    }
    return results.map(result => result && result.result);
}));
/**
 * Sends a sequence of LSP requests: initialize, request (the arg), shutdown, exit. The result from the request
 * (the arg) is returned. If the request arg is not given, it is omitted and the result from initialize is
 * returned.
 */
const sendLSPRequest = (ctx, request) => httpSendLSPRequest(ctx, request).pipe(map(results => results[request ? 1 : 0]));
/**
 * Query the server's capabilities.
 */
export const fetchServerCapabilities = memoizeObservable((pos) => sendLSPRequest(pos).pipe(map(result => result.capabilities)), cacheKey);
/** Callers should use features.getXdefinition instead. */
export const fetchXdefinition = memoizeObservable((ctx) => sendLSPRequest(ctx, {
    method: 'textDocument/xdefinition',
    params: {
        textDocument: {
            uri: `git://${ctx.repoPath}?${ctx.commitID}#${ctx.filePath}`,
        },
        position: {
            character: ctx.position.character - 1,
            line: ctx.position.line - 1,
        },
    },
}).pipe(map((result) => result[0])), cacheKey);
/** Callers should use features.getXreferences instead. */
export const fetchXreferences = memoizeObservable((ctx) => sendLSPRequest({
    repoPath: ctx.repoPath,
    rev: ctx.rev,
    commitID: ctx.commitID,
    mode: ctx.mode,
}, {
    method: 'workspace/xreferences',
    params: {
        hints: ctx.hints,
        query: ctx.query,
        limit: ctx.limit,
    },
}).pipe(map((refInfos) => refInfos.map(refInfo => refInfo.reference))), options => cacheKey(options) + ':' + JSON.stringify([options.query, options.hints, options.limit]));
function cacheKey(sel) {
    return `${makeRepoURI(sel)}:mode=${sel.mode}`;
}
//# sourceMappingURL=lsp.js.map